from typing import List, Tuple, Optional, Any

from GUIBRUSHR.GUI.LAYOUT.MyPanel import MyPanel
from GUIBRUSHR.GUI.WIDGET.MyLabel import MyLabel
from GUIBRUSHR.GUI.WIDGET.MyDropDown import MyDropdown
from GUIBRUSHR.GUI.WIDGET.MyCheckBox import MyCheckBox
from GUIBRUSHR.GUI.WIDGET.MyEntry import MyEntry
from numpy import where

# Constants for element configuration
DEFAULT_PARAM_VALUE = 2
DEFAULT_VMR_VALUE = 2
DEFAULT_CHECKBOX_VALUE = 1

class ParametersGUI:
    """
    A GUI panel for managing parameter inputs and configurations.

    This class creates and manages a row of input widgets for parameters including:
    - Molecular/Element selection
    - Presence checkbox
    - Value input
    - Scale input
    - Range inputs (min/max)
    - Mass input
    - Prior sigma input
    - VMR (Volume Mixing Ratio) settings
    """

    def __init__(
            self,
            parent: Any,
            row: int,
            color: str,
            elements: List[Any],
            status: str,
            chemical_formula: Optional[str] = None,
            molecs = None,
            isotopes: Optional[dict] = None,
            opacity_line_lists_HR: Optional[dict] = None,
            opacity_line_lists_LR: Optional[dict] = None,
            isotope_masses: Optional[dict] = None,
            elems: Optional[List[str]] = None,
            condensed_molecs_list=None,
            condensed_molecs_masses=None,
            condensed_molecs_names=None,
            condensed_visualization_name=None
    ) -> None:
        """
        Initialize the ParametersGUI panel.

        Args:
            parent: Parent widget
            row: Row number in parent widget
            color: Color scheme for widgets
            elements: List of element configurations [name, present, molec, value, scale, range_min, range_max, rayleigh, bestpars, mass, prior, constant_vmr]
            status: Initial status of widgets
            chemical_formula: Optional chemical formula
            molecs: Optional list of molecules
            isotopes: Optional dictionary of isotopes
            opacity_line_lists_HR: Optional dictionary of line lists at HR
            opacity_line_lists_LR: Optional dictionary of line lists at LR
            isotope_masses: Optional dictionary of isotope masses
            elems: Optional list of elements
        """
        self._index_for_lr_list = None
        self.use_hr_lineslist_for_lr = False
        self.dropdown_opacity_line_list_LR = None
        self.parent = parent
        self.elems = elems
        self.row = row
        self.color = color
        self.elements = elements

        # Initialize widget attributes
        self.label_name: Optional[MyLabel] = None
        self.dropdown_isotope: Optional[MyDropdown] = None
        self.dropdown_opacity_line_list_HR: Optional[MyDropdown] = None
        self.dropdown_elems = None
        self.dropdown_condensed = None
        self.default_param = False
        self.default_VMR = False
        self.selected_molec = 0
        self.selected_condensed = 0
        # col = 0
        self.is_first = True
        self.chemical_formula = None
        self.is_condensed = condensed_molecs_list is not None

        # Initialize widgets
        self._initialize_name_widgets(
            chemical_formula, molecs, isotopes, opacity_line_lists_HR, opacity_line_lists_LR, isotope_masses,
            condensed_molecs_list, condensed_molecs_masses, condensed_molecs_names, condensed_visualization_name
        )
        self._initialize_parameter_widgets()
        self._initialize_additional_widgets()

        # Set initial status
        self.disable_param_status(status)

    def _initialize_name_widgets(
            self,
            chemical_formula: Optional[str],
            molecs: Optional[List[str]],
            isotopes: Optional[dict],
            opacity_line_lists_HR: Optional[dict],
            opacity_line_lists_LR: Optional[dict],
            isotope_masses: Optional[dict],
            condensed_molecs_list=None,
            condensed_molecs_masses=None,
            condensed_molecs_names=None,
            condensed_visualization_name=None

    ) -> None:
        """Initialize the name-related widgets based on the input type."""
        col = 0
        self.mass = self.elements[9]  # Default mass from elements list

        if molecs is not None:
            self._setup_molecular_widgets(molecs, isotopes, opacity_line_lists_HR, opacity_line_lists_LR, isotope_masses, col)
            self.mass = self.isotope_masses[self.isotopes[self.molecs[0]][0]]
            chemical_formula = self.molecs[0]
        elif condensed_molecs_list is not None:
            self.mass = condensed_molecs_masses[0]
            self.condensed_molecs_masses = condensed_molecs_masses
            self.condensed_molecs_list = condensed_molecs_list
            self.condensed_molecs_names = condensed_molecs_names
            self.condensed_visualization_name = condensed_visualization_name
            #
            self.dropdown_condensed = MyDropdown(self.parent, self.row, col, self.condensed_visualization_name, columnspan=1, color=self.color)
            self.dropdown_condensed.chosen_var.trace("w", lambda *args: self.on_select_condensed())
            # mass = self.condensed_molecs_masses[0]
            chemical_formula = self.condensed_molecs_list[0]
            col += 1
        elif self.elems is not None:
            self.dropdown_elems = MyDropdown(self.parent, self.row, col, self.elems, columnspan=1, color=self.color)
        else:
            self.label_name = MyLabel(self.parent, self.row, col, label_text=self.elements[0], columnspan=3, color=self.color)

        self.chemical_formula = chemical_formula

    def _setup_molecular_widgets(
            self,
            molecs: List[str],
            isotopes: dict,
            opacity_line_lists_HR: dict,
            opacity_line_lists_LR: dict,
            isotope_masses: dict,
            col: int
    ) -> None:
        """Setup widgets for molecular selection."""
        self.molecs = molecs
        self.isotopes = isotopes
        self.opacity_line_lists_HR = opacity_line_lists_HR
        self.opacity_line_lists_LR = opacity_line_lists_LR
        self.isotope_masses = isotope_masses

        # Setup molecule dropdown
        self.dropdown_molec = MyDropdown(self.parent, self.row, col, self.molecs, columnspan=1, color=self.color)
        self.dropdown_molec.chosen_var.trace("w", lambda *args: self.on_select_molec())
        col += 1

        # Setup isotope dropdown
        self.dropdown_isotope = MyDropdown(
            self.parent, self.row, col,
            self.isotopes[self.molecs[0]],
            columnspan=1,
            color=self.color
        )
        self.dropdown_isotope.chosen_var.trace("w", lambda *args: self.on_select_isotope())
        col += 1

        self.panel_opac = MyPanel(self.parent, self.color, self.row, col)
        self._index_for_lr_list = self.isotopes[self.molecs[0]][0]

        # Setup sub-isotope dropdown
        self.dropdown_opacity_line_list_HR = MyDropdown(
            self.panel_opac, 0, 1,
            self.opacity_line_lists_HR[self._index_for_lr_list],
            columnspan=2,
            label_text="HR",
            color=self.color
        )

        # Setup sub-isotope dropdown
        self.dropdown_opacity_line_list_LR = MyDropdown(
            self.panel_opac, 1, 1,
            self.opacity_line_lists_LR[self._index_for_lr_list],
            columnspan=2,
            label_text="LR",
            color=self.color
        )

    def _initialize_parameter_widgets(self) -> None:
        """Initialize the parameter-related widgets."""
        col = 3

        # Presence checkbox
        if self.elements[1] == DEFAULT_PARAM_VALUE:
            self.checkbox_presence = MyCheckBox(self.parent, self.row, col, initial_value=DEFAULT_CHECKBOX_VALUE)
            self.checkbox_presence.set_status("disabled")
            self.default_param = True
        else:
            self.checkbox_presence = MyCheckBox(self.parent, self.row, col, initial_value=self.elements[1])
        col += 1

        # Value input
        self.input_value = MyEntry(self.parent, self.row, col, self.elements[3], columnspan=1, color=self.color)
        col += 1

        # Scale input
        self.input_scale = MyEntry(self.parent, self.row, col, self.elements[4], columnspan=1, color=self.color)
        col += 1

        # Range inputs
        self.input_range_min = MyEntry(self.parent, self.row, col, self.elements[5], columnspan=1, color=self.color)
        col += 1
        self.input_range_max = MyEntry(self.parent, self.row, col, self.elements[6], columnspan=1, color=self.color)
        col += 1

        # Best parameters checkbox
        self.checkbox_bestpars = MyCheckBox(self.parent, self.row, col, initial_value=self.elements[8])
        col += 1

        # Mass (only for molecules/condensed)
        has_mass = self.elements[9] is not None and self.elements[9] != -999
        if has_mass:
            self.input_mass = MyEntry(self.parent, self.row, col, self.mass, columnspan=1, color=self.color)
        else:
            self.input_mass = None
            self._mass_fixed = -999
            MyLabel(self.parent, self.row, col, label_text="—", columnspan=1, color=self.color)

        col += 1
        # Sigma prior input
        self.input_sigma_prior = MyEntry(self.parent, self.row, col, self.elements[10], columnspan=1, color=self.color)
        col += 1

        # Constant VMR checkbox (only for molecules/condensed)
        if has_mass:
            if self.elements[11] == DEFAULT_VMR_VALUE:
                self.checkbox_constant_VMR = MyCheckBox(self.parent, self.row, col, initial_value=DEFAULT_CHECKBOX_VALUE)
                self.checkbox_constant_VMR.set_status("disabled")
                self.default_VMR = True
            else:
                self.checkbox_constant_VMR = MyCheckBox(self.parent, self.row, col, initial_value=self.elements[11])
        else:
            self.checkbox_constant_VMR = None
            self._constant_vmr_fixed = 1
            self.default_VMR = True
            MyLabel(self.parent, self.row, col, label_text="—", columnspan=1, color=self.color)

        # type_params
        col += 1
        self.type_params = self.elements[12]
        self.label_type_params = MyLabel(self.parent, self.row, col, label_text=self.type_params, columnspan=1, color=self.color)

        # Rayleigh dropdown (only for molecules with mass, not condensed)
        col += 1
        if has_mass and not self.is_condensed:
            self.dropdown_rayleigh = MyDropdown(
                self.parent, self.row, col, ["0", "1", "2"], color=self.color, columnspan=1
            )
            self.dropdown_rayleigh.chosen_var.set(str(int(self.elements[7])))
            self._rayleigh_fixed = None
        else:
            self.dropdown_rayleigh = None
            self._rayleigh_fixed = 0
            MyLabel(self.parent, self.row, col, label_text="—", columnspan=1, color=self.color)

    def get_rayleigh_value(self):
        """Get the rayleigh value: from dropdown if molecule, otherwise fixed value."""
        if self.dropdown_rayleigh is not None:
            return int(self.dropdown_rayleigh.get_value())
        return self._rayleigh_fixed

    def get_mass_value(self):
        """Get the mass value: from widget if molecule/condensed, otherwise fixed value."""
        if self.input_mass is not None:
            return float(self.input_mass.get_value())
        return self._mass_fixed

    def get_constant_vmr_value(self):
        """Get the constant VMR value: from widget if molecule/condensed, otherwise fixed value."""
        if self.checkbox_constant_VMR is not None:
            return self.checkbox_constant_VMR.get_value()
        return self._constant_vmr_fixed

    def _initialize_additional_widgets(self) -> None:
        """Initialize any additional widgets and attributes."""
        self.is_molec = self.elements[2]

    def disable_param_status(self, status: str) -> None:
        """
        Update the status of all parameter widgets.

        Args:
            status: The new status to set ('disabled' or 'normal')
        """
        if not self.is_first:
            self.checkbox_presence.set_value(0 if status == "disabled" else 1)
        else:
            self.is_first = False

        if not self.default_param:
            self.checkbox_presence.set_status(status)
        if not self.default_VMR and self.checkbox_constant_VMR is not None:
            self.checkbox_constant_VMR.set_status(status)

        # Update status for all input widgets
        widgets_to_update = [
            self.input_scale,
            self.input_value,
            self.checkbox_bestpars,
            self.input_range_max,
            self.input_range_min,
            self.input_sigma_prior,
        ]

        for widget in widgets_to_update:
            widget.set_status(status)

        if self.input_mass is not None:
            self.input_mass.set_status(status)
        if self.dropdown_rayleigh is not None:
            self.dropdown_rayleigh.set_status(status)

    def on_select_molec(self) -> None:
        """Handle molecule selection change."""
        selected_index = where(self.molecs == self.dropdown_molec.get_value())[0][0]

        # Clean and update isotope widgets
        self.dropdown_isotope.clean_widget()
        self.dropdown_opacity_line_list_HR.clean_widget()
        self.selected_molec = selected_index
        self.chemical_formula = self.molecs[self.selected_molec]

        # Update mass
        mass = self.isotope_masses[self.isotopes[self.molecs[selected_index]][0]]
        self.input_mass.set_value(mass)

        # Create new isotope dropdowns
        self.dropdown_isotope = MyDropdown(
            self.parent, self.row, 1,
            self.isotopes[self.molecs[selected_index]],
            columnspan=1
        )
        self.dropdown_isotope.chosen_var.trace("w", lambda *args: self.on_select_isotope())

        index = self.isotopes[self.molecs[selected_index]][0]
        self._index_for_lr_list = index

        self.dropdown_opacity_line_list_HR = MyDropdown(
            self.panel_opac, 0, 1,
            self.opacity_line_lists_HR.get(index, ["None"]),
            columnspan=2,
            label_text="HR",
            color=self.color
        )
        self.select_LR_list(True)

    def on_select_isotope(self) -> None:
        """Handle isotope selection change."""
        selected_index = where(
            self.isotopes[self.molecs[self.selected_molec]] == self.dropdown_isotope.get_value()
        )[0][0]

        # Clean and update sub-isotope widget
        self.dropdown_opacity_line_list_HR.clean_widget()

        index = self.isotopes[self.molecs[self.selected_molec]][selected_index]
        self._index_for_lr_list = index

        # Update mass
        mass = self.isotope_masses[index]
        self.input_mass.set_value(mass)

        self.dropdown_opacity_line_list_HR = MyDropdown(
            self.panel_opac, 0, 1,
            self.opacity_line_lists_HR.get(index, ["None"]),
            columnspan=2,
            label_text="HR",
            color=self.color
        )

        self.select_LR_list(True)


    def select_LR_list(self, internal_call, use_hr_lineslist_for_lr: bool = False):
        if not internal_call:
            self.use_hr_lineslist_for_lr = use_hr_lineslist_for_lr
        self.dropdown_opacity_line_list_LR.clean_widget()
        list_lr = self.opacity_line_lists_HR.get(self._index_for_lr_list, ["None"]) if self.use_hr_lineslist_for_lr else self.opacity_line_lists_LR.get(self._index_for_lr_list, ["None"])
        # Setup sub-isotope dropdown
        self.dropdown_opacity_line_list_LR = MyDropdown(
            self.panel_opac, 1, 1,
            list_lr,
            columnspan=2,
            label_text="LR",
            color=self.color
        )


    def on_select_condensed(self):
        # Get the current selection's index
        selected_index = where(self.condensed_visualization_name == self.dropdown_condensed.get_value())[0][0]
        #
        self.selected_condensed = selected_index
        self.chemical_formula = self.condensed_molecs_list[selected_index]
        #
        mass = self.condensed_molecs_masses[selected_index]
        self.input_mass.set_value(mass)

    def get_name(self) -> Tuple[str, Optional[str]]:
        """
        Get the current name selection.

        Returns:
            Tuple containing:
            - The selected name (from label, element dropdown, or sub-isotope)
            - The isotope name (if applicable, otherwise None)
        """
        if self.label_name is not None:
            return self.label_name.get_text(), None
        elif self.dropdown_elems is not None:
            return self.dropdown_elems.get_value(), None
        elif self.dropdown_condensed is not None:
            return self.condensed_molecs_names[self.selected_condensed], None
        else:
            return self.dropdown_opacity_line_list_HR.get_value(), self.dropdown_isotope.get_value()
