
import time
import qwiic_scmd
import qwiic_i2c

from __future__ import print_function
from flask_babel import lazy_gettext
from qwiic_scmd import QwiicSCMD

from mycodo.config_translations import TRANSLATIONS
from mycodo.databases.models import OutputChannel
from mycodo.outputs.base_output import AbstractOutput
from mycodo.utils.constraints_pass import constraints_pass_percent
from mycodo.utils.constraints_pass import constraints_pass_positive_value
from mycodo.utils.database import db_retrieve_table_daemon
from mycodo.utils.influx import add_measurements_influxdb




# Measurements questo è il dizionario che serve per creare i valori di controllo tempo, ml ecc
measurements_dict = {
    0: {
        'measurement': 'duration_time',
        'unit': 's',
        'name': 'Pump On',
    },
    1: {
        'measurement': 'volume',
        'unit': 'ml',
        'name': 'Dispense Volume',
    },
    2: {
        'measurement': 'duration_time',
        'unit': 's',
        'name': 'Dispense Duration',
    },
    3: {
        'measurement': 'duration_time',
        'unit': 's',
        'name': 'Pump On',
    },
    4: {
        'measurement': 'volume',
        'unit': 'ml',
        'name': 'Dispense Volume',
    },
    5: {
        'measurement': 'duration_time',
        'unit': 's',
        'name': 'Dispense Duration',
    }
}

#dizionario per la definizione dei canali della pompa
channels_dict = {
    0: {
        'name': 'Channel A',
        'types': ['volume', 'on_off'],
        'measurements': [0, 1, 2]
    },
    1: {
        'name': 'Channel B',
        'types': ['volume', 'on_off'],
        'measurements': [3, 4, 5]
    }
}

# Output information Dizionario che contiene tutte le info riguardo la pompa
OUTPUT_INFORMATION = {
    # A unique output name used to distinguish it from others
    'output_name_unique': 'sparkfun_qwiic_serial_control_motor_driver ',
    # A friendly/common name for the output to display to the user
    'output_name': "{}: Sparkfun qwiic serial control motor driver ".format(lazy_gettext('Peristaltic Pump')),
    'output_manufacturer': 'Sparkfun ',
    # Optional library name (for outputs that are named the same but use different libraries)
    'output_library': 'qwiic_i2c',
    # The dictionaries of measurements and channels for this output
    'measurements_dict': measurements_dict,
    'channels_dict': channels_dict,
    # Type of output. Options: "on_off", "pwm", "volume"
    'output_types': ['volume', 'on_off'],

    'url_manufacturer': ' https://learn.sparkfun.com/tutorials/hookup-guide-for-the-qwiic-motor-driver/all',

    'message': 'Controls the Sparkfun qwiic Motor Driver Board. This output can also dispense volumes of fluid if the motors are attached to peristaltic pumps.',

    # Form input options that are enabled or disabled
    'options_enabled': [
        'i2c_location',
        'button_on',            # Shows a button to turn the output on
        'button_send_volume',
        'button_send_duration'  # Shows an input field and an button to turn on for a duration
    ],
    'options_disabled': [
        'interface'
    ],  # Show the interface (as a disabled input)

    'dependencies_module': [
        ('pip-pypi', 'qwiic_i2c'), 
        ('pip-pypi', 'qwiic_scmd')
    ],

    'interfaces': ['I2C'],
    'i2c_address_editable': True,
    'i2c_address_default': '0x5D',
    'i2c_location': ['0x5D, 0x58, 0x59, 0x5A, 0x5C'],
    

    'custom_options_message': "To accurately dispense specific volumes, the following options need to be correctly "
                              "set. To determine the flow rate of your pump, first purge the fluid line to remove "
                              "air. Next, turn the pump on for 60 seconds and collect the fluid that's dispensed. "
                              "Last, measure and enter the amount of fluid that was dispensed, in ml, into the "
                              "Fastest Rate (ml/min) field. Your pump should now be calibrated to dispense volumes "
                              "accurately. "
                              "Since Peristaltic Pump Output controllers are capable of accepting multiple different "
                              "dispersal value types, Default Dispersal Method must be set in order to specify whether "
                              "the peristaltic pump should output for a duration or a specific volume when other "
                              "controllers (such as PID controllers) send a value instructing it to dispense.",


    # Custom options that can be set by the user in the web interface.
    'custom_options': [
        {
            'id': 'bool_value',
            'type': 'bool',
            'default_value': True,  # True = avanti, False = indietro
            'name': 'Direzione',
            'phrase': 'Imposta la direzione (Avanti = True, Indietro = False)'
        },
        {
            'id': 'float_value',
            'type': 'float',
            'default_value': 100.0,
            'constraints_pass': constraints_pass_positive_value,  # Controlla che il valore sia positivo
            'name': 'Velocità',
            'phrase': 'Imposta la velocità (0 - 255)',
            'range': [0, 255]  # Imposta il range di velocità
        },
    ],


    #Azioni personalizzate che appariranno in cima alle opzioni dell'interfaccia utente.
    # I pulsanti devono avere una funzione con lo stesso nome che verrà eseguita quando il pulsante viene premuto.
    # quando il pulsante viene premuto. I valori di input saranno passati al pulsante in un 
    # dizionario. Vedere la funzione input_button() alla fine di questo modulo. 
    'custom_channel_options': [
        {
            'id': 'name',
            'type': 'text',
            'default_value': 'Motore 0',
            'required': True,
            'name': 'Nome del motore',
            'phrase': 'Imposta il nome per il motore'
        },
        {
            'id': 'custom_selection',
            'type': 'select_custom_choices',
            'default_value': '',
            'name': 'Selezione personalizzata',
            'phrase': 'Una selezione definita nel codice dell’Output'
        },
        {
            'id': 'name',
            'type': 'text',
            'default_value': '',
            'required': False,
            'name': TRANSLATIONS['name']['title'],
            'phrase': TRANSLATIONS['name']['phrase']
        },
        {
            'id': 'motor_speed',
            'type': 'integer',
            'default_value': 100,
            'constraints_pass': constraints_pass_percent,
            'name': 'Motor Speed (0 - 100)',
            'phrase': 'The motor output that determines the speed'
        },
        {
            'id': 'flow_mode',
            'type': 'select',
            'default_value': 'fastest_flow_rate',
            'options_select': [
                ('fastest_flow_rate', 'Fastest Flow Rate'),
                ('specify_flow_rate', 'Specify Flow Rate')
            ],
            'name': lazy_gettext('Flow Rate Method'),
            'phrase': lazy_gettext('The flow rate to use when pumping a volume')
        },
        {
            'id': 'flow_rate',
            'type': 'float',
            'default_value': 10.0,
            'constraints_pass': constraints_pass_positive_value,
            'name': 'Desired Flow Rate (ml/min)',
            'phrase': 'Desired flow rate in ml/minute when Specify Flow Rate set'
        },
        {
            'id': 'fastest_dispense_rate_ml_min',
            'type': 'float',
            'default_value': 100.0,
            'constraints_pass': constraints_pass_positive_value,
            'name': 'Fastest Rate (ml/min)',
            'phrase': 'The fastest rate that the pump can dispense (ml/min)'
        }
    ],
}


#copio da dummy e modifico con chatgpt

class OutputModule(AbstractOutput):
    """An output support class that operates an output."""
    def __init__(self, output, testing=False):
        super().__init__(output, testing=testing, name=__name__)

        # Initialize custom option variables to None
        self.motor = None
        self.currently_dispensing = False

#da capire a cosa serve sta parte '''
        
        output_channels = db_retrieve_table_daemon(
            OutputChannel).filter(OutputChannel.output_id == self.output.unique_id).all()
        self.options_channels = self.setup_custom_channel_options_json(
            OUTPUT_INFORMATION['custom_channel_options'], output_channels)

        # Set custom option variables to defaults or user-set values
        self.setup_custom_options(
            OUTPUT_INFORMATION['custom_options'], output)

        # Set custom channel options to defaults or user-set values
        output_channels = db_retrieve_table_daemon(
            OutputChannel).filter(OutputChannel.output_id == self.output.unique_id).all()
        self.options_channels = self.setup_custom_channel_options_json(
            OUTPUT_INFORMATION['custom_channel_options'], output_channels)
        

    def initialize(self):
        """inizializza l'output all' avvio di Mycodo."""
        # Variables set by the user interface
        import qwiic_scmd
        
        self.setup_output_variables(OUTPUT_INFORMATION)
        self.motor = None
     
        # Inizializzazione del controller dei motori
        self.motor_driver = QwiicScmd()

        if self.motor_driver.is_connected():
            self.motor_driver.begin()
            self.motor_driver.enable()
            self.output_setup = True
            self.logger.info("Motore inizializzato correttamente")
        else:
            self.logger.error("Controller non rilevato")
            self.output_setup = False
        for each_channel in channels_dict:
            self.logger.info(
                f"CH{each_channel}: "
                f"{self.options_channels['name'][each_channel]}: "
                f"custom_selection = {self.options_channels['custom_selection'][each_channel]}")


    def output_switch(self, state, output_type=None, amount=None, duty_cycle=None, output_channel=None):
        """Accende o spegne l'output (motore) o imposta una quantità o ciclo di lavoro."""
        if not self.output_setup:
            self.logger.error("Il modulo non è stato configurato correttamente")
            return
        
        # Controllo dell'accensione o spegnimento del motore
        if state == 'on':
            self.logger.info("Motore acceso")
            self.motor_driver.set_drive(0, 0, 255)  # Avvia motore 0 alla massima velocità (255)
            self.output_states[output_channel] = True
        elif state == 'off':
            self.logger.info("Motore spento")
            self.motor_driver.set_drive(0, 0, 0)  # Ferma il motore 0
            self.output_states[output_channel] = False

    def is_on(self, output_channel=None):
        """Restituisce lo stato del motore."""
        if self.is_setup():
            return self.output_states.get(output_channel, False)

    def disable(self):
        """Disabilita il controller motore."""
        if self.motor_driver:
            self.motor_driver.disable()
            self.logger.info("Motore disabilitato")





