"""
Frame for managing target-related operations in the GUI.
This module handles the creation and management of exoplanet targets,
including their physical parameters and observational data.
"""

from tkinter import messagebox, filedialog
import numpy as np
import pandas as pd
import pickle
from pathlib import Path

from matplotlib import pyplot as plt
from petitRADTRANS import physical_constants as phys_const

from GUIBRUSHR.GUI.DataInterface import DataInterface
from GUIBRUSHR.GUI.DataInterface.DBSQLite3 import DBSQLite3
from GUIBRUSHR.GUI.DataInterface.DataInterface import (
    get_target_list,
    insert_night_in_target,
    insert_instrument_lr_in_target
)
from GUIBRUSHR.GUI.LAYOUT.MyPanel import MyPanel
from GUIBRUSHR.GUI.WIDGET.MyButton import MyButton
from GUIBRUSHR.GUI.WIDGET.MyDropDown import MyDropdown
from GUIBRUSHR.GUI.WIDGET.MyEntry import MyEntry
from GUIBRUSHR.GUI.WIDGET.MyTextField import MyTextField
from GUIBRUSHR.General_Constants.FunctionsAndConstants.Constant_Variables import ConstantVariables
from GUIBRUSHR.General_Constants.Classes.HelpButton import HelpButton
from GUIBRUSHR.General_Constants.FunctionsAndConstants.general_functions import compute_transit_durations


class FrameTarget(MyPanel):
    """
    A panel for managing exoplanet targets and their associated data.
    
    This class provides functionality to:
    - Add new exoplanet targets with their physical parameters
    - Manage observational nights and instruments
    - Handle database interactions for target data
    """

    def __init__(self, parent, color, row, column, path_default, frame_input, window, **kwargs):
        """Initialize the FrameTarget panel with all necessary components."""
        super().__init__(parent, color, row, column, **kwargs)
        
        # Store instance variables
        self.dropdown_tbl_lr_instruments = None
        self.list_hr_instruments = None
        self.list_lr_instruments = None
        self.dropdown_instruments = None
        self.dropdown_target = None
        self.target_list = None
        self.path_folder_targets = frame_input.frame_path.path_folder_targets.get_text()
        self.global_exc = 0
        self.frame_input = frame_input
        self.path_default = path_default
        self.window = window
        self.color = color

        # Initialize panels
        self._init_panels()
        # Initialize input fields
        self._init_input_fields()
        # Initialize buttons and dropdowns
        self._init_controls()

    def _init_panels(self):
        """Initialize the main panel columns."""
        # Top panel: Target insert form (spans full width)
        self.column1 = MyPanel(self, self.color, 0, 0, columnspan=2)
        # Bottom left panel: Add Night/Instrument
        self.column2 = MyPanel(self, self.color, 1, 0)
        # Bottom right panel: TBL to PKL conversion
        self.column3 = MyPanel(self, self.color, 1, 1)

    def _init_input_fields(self):
        """Initialize all input fields for target parameters."""
        # Help text dictionary
        help_text = {
            "Exoplanet": "Name of the exoplanet target. Use standard nomenclature (e.g., HD 189733 b, WASP-76 b). This name will be used to create the target directory structure and must match folder naming conventions.",

            "Radius [R_J]": "Planetary radius in Jupiter radii (R_J). Used to calculate surface gravity and transit depth. Typical hot Jupiters: 1.0-1.5 R_J.",

            "Mass [M_J]": "Planetary mass in Jupiter masses (M_J). Used with the stellar mass to calculate the Keplerian semi-amplitude (Kp). Typical hot Jupiters: 0.5-2.0 M_J.",

            "T14 [hours]": "Total transit duration in hours, from first to fourth contact. Used to calculate the phase limit for in-transit observations. This defines the region where atmospheric signals are expected.",

            "T Eq [K]": "Equilibrium temperature of the planet in Kelvin. Used for initial atmospheric modeling and molecule selection. Typical hot Jupiters: 1200-2500 K.",

            "Stellar Radius [R_S]": "Stellar radius in solar radii (R_☉). Required for calculating transit parameters and atmospheric scale heights.",

            "Stellar Mass [M_S]": "Stellar mass in solar masses (M_☉). Used with planetary mass to calculate orbital dynamics and the Keplerian semi-amplitude (Kp).",

            "Stellar Teff [K]": "Effective temperature of the host star in Kelvin. Used for stellar spectrum modeling and contribution removal in atmospheric retrievals.",

            "HJD0 [days]": "Mid-transit time in Heliocentric Julian Date (HJD). Reference epoch for calculating orbital phases. Must be precisely determined from photometry.",

            "Period [days]": "Orbital period of the planet in days. Used to calculate orbital phases and velocities. Must be precisely known for high-resolution spectroscopy.",

            "VSys [km/s]": "Systemic velocity of the system in km/s (relative to the solar system barycenter). This is the center-of-mass radial velocity and must be corrected for barycentric motion.",

            "Ecc": "Orbital eccentricity (0 = circular, 0 < e < 1 = elliptical). Most transiting exoplanets have near-circular orbits (e ≈ 0). Set to 0 if unknown.",

            "Opi [rad]": "Argument of periastron (ω) in radians. Defines the orientation of the orbital ellipse. Default: π/2 for circular orbits. Only relevant if eccentricity > 0.",

            "RA [deg]": "Right Ascension in degrees (J2000). Celestial coordinate for calculating barycentric corrections and observatory planning.",

            "Dec [deg]": "Declination in degrees (J2000). Celestial coordinate for calculating barycentric corrections and observatory planning.",

            "a/Rs": "Semi-major axis to stellar radius ratio (a/R*). This dimensionless parameter is crucial for transit modeling and determining atmospheric scale height. Can be calculated from orbital period, stellar mass, and stellar radius using Kepler's third law.",

            "Projected Obliquity [deg]": "Projected stellar obliquity (λ) in degrees. The angle between the stellar spin axis and the orbital angular momentum vector projected onto the sky plane. Measured through the Rossiter-McLaughlin effect during transits.",

            "Inclination [deg]": "Orbital inclination in degrees. The angle between the orbital plane and the plane of the sky. 90° corresponds to an edge-on orbit (transiting geometry). Typically derived from transit light curve modeling.",

            "v sin(i) [km/s]": "Projected stellar rotational velocity in km/s. The stellar equatorial rotation velocity multiplied by sin(i), where i is the stellar inclination angle. Measured from spectral line broadening and used to constrain stellar rotation and the Rossiter-McLaughlin effect.",
        }

        # Standard entry width for consistency
        entry_w = 15

        # Create help button (spans all 5 rows)
        self.help_button = HelpButton(
            self.column1, 0, 0,
            "Target Parameters Help",
            help_text,
            columnspan=1
        )
        self.help_button.button.grid(rowspan=5)

        # Row 0: Identification + Planet Parameters
        self.textfield_target = MyTextField(self.column1, 0, 1, "", "Exoplanet:".ljust(22), width=15, columnspan=2)
        self.entry_radius = MyEntry(self.column1, 0, 3, "", color=self.color,
                                    label_text=r'Radius [R_J]:'.ljust(19),
                                    entry_width=entry_w, columnspan=2)
        self.entry_mass = MyEntry(self.column1, 0, 5, "", color=self.color,
                                  label_text=r'Mass [M_J]:'.ljust(17),
                                  entry_width=entry_w, columnspan=2)
        self.entry_teq = MyEntry(self.column1, 0, 7, "", color=self.color,
                                 label_text=r'T Eq [K]:'.ljust(17),
                                 entry_width=entry_w, columnspan=2)

        # Row 1: Star Parameters
        self.entry_stellar_radius = MyEntry(self.column1, 1, 1, "", color=self.color,
                                            label_text=r'Stellar Radius [R_S]:'.ljust(22),
                                            entry_width=entry_w, columnspan=2)
        self.entry_stellar_mass = MyEntry(self.column1, 1, 3, "", color=self.color,
                                          label_text=r'Stellar Mass [M_S]:'.ljust(19),
                                          entry_width=entry_w, columnspan=2)
        self.entry_stellar_teff = MyEntry(self.column1, 1, 5, "", color=self.color,
                                          label_text=r'Stellar Teff [K]:'.ljust(17),
                                          entry_width=entry_w, columnspan=2)
        self.entry_v_sini = MyEntry(self.column1, 1, 7, "", color=self.color,
                                    label_text=r'v*sin(i) [km/s]:'.ljust(17),
                                    entry_width=entry_w, columnspan=2)

        # Row 2: Orbital Parameters
        self.entry_period = MyEntry(self.column1, 2, 1, "", color=self.color,
                                    label_text=r'Period [days]:'.ljust(22),
                                    entry_width=entry_w, columnspan=2)
        self.entry_hjd0 = MyEntry(self.column1, 2, 3, "", color=self.color,
                                  label_text=r'HJD0 [days]:'.ljust(19),
                                  entry_width=entry_w, columnspan=2)
        self.entry_vsys = MyEntry(self.column1, 2, 5, "", color=self.color,
                                  label_text=r'VSys [km/s]:'.ljust(17),
                                  entry_width=entry_w, columnspan=2)
        self.entry_ecc = MyEntry(self.column1, 2, 7, "", color=self.color,
                                 label_text=r'Ecc:'.ljust(17),
                                 entry_width=entry_w, columnspan=2)
        self.entry_opi = MyEntry(self.column1, 2, 9, str(np.pi / 2), color=self.color,
                                 label_text=r'Opi [rad]:'.ljust(10),
                                 entry_width=entry_w, columnspan=2)

        # Row 3: Geometry & Coordinates
        self.entry_ra = MyEntry(self.column1, 3, 1, "", color=self.color,
                                label_text=r'RA [deg]:'.ljust(22),
                                entry_width=entry_w, columnspan=2)
        self.entry_dec = MyEntry(self.column1, 3, 3, "", color=self.color,
                                 label_text=r'Dec [deg]:'.ljust(19),
                                 entry_width=entry_w, columnspan=2)
        self.entry_a_Rs_ratio = MyEntry(self.column1, 3, 5, "", color=self.color,
                                        label_text=r'a/Rs:'.ljust(17),
                                        entry_width=entry_w, columnspan=2)
        self.entry_inclination = MyEntry(self.column1, 3, 7, "", color=self.color,
                                         label_text=r'Incl. [deg]:'.ljust(17),
                                         entry_width=entry_w, columnspan=2)
        self.entry_projected_obliquity = MyEntry(self.column1, 3, 9, "", color=self.color,
                                                 label_text=r'Proj. Obl. [deg]:'.ljust(17),
                                                 entry_width=entry_w, columnspan=2)

    def _init_controls(self):
        """Initialize buttons and dropdown menus."""
        # Add target button (centered in row 4)
        self.button_add_target = MyButton(
            self.column1, 4, 5, r'Add Target',
            bg="#1e4fda", color_panel=self.color, command=self.add_target,
            columnspan=4, sticky="", width=20
        )

        # Load initial data from database and update UI components
        self.target_list = get_target_list(self.path_folder_targets)

        DB = DBSQLite3(self.path_default)
        all_instruments, resolutions, _, _, _ = DB.get_instruments()
        DB.close_DB()

        # Filter for LR instruments only
        self.list_hr_instruments = []
        self.list_lr_instruments = []
        if all_instruments and resolutions:
            for inst, res in zip(all_instruments, resolutions):
                if res == "HR":
                    self.list_hr_instruments.append(inst)
                if res == "LR":
                    self.list_lr_instruments.append(inst)

        if not self.list_hr_instruments:
            self.list_hr_instruments = ["None"]
        if not self.list_lr_instruments:
            self.list_lr_instruments = ["None"]

        # Dropdown menus
        self.dropdown_target = MyDropdown(
            self.column2, 0, 1, self.target_list, "Target:", color=self.color, columnspan=2
        )
        self.dropdown_instruments = MyDropdown(
            self.column2, 0, 3, self.list_hr_instruments, "Instrument:", color=self.color,
            columnspan=2
        )
        self.dropdown_rad_mode = MyDropdown(
            self.column2, 0, 5, ConstantVariables.LIST_RAD_MODE,
            "Rad. Transf. Mode:", initial_value=0,
            color=self.color, columnspan=2
        )
        
        # Column 2 Help Text
        help_text_column2 = {
            "Target": "Select an existing target from the database to add observational nights folder",
            "HR Instrument": "Select the instrument used for observations. The instrument must be previously added to the database with its characteristics (resolution, wavelength range, HWHM).",
            "Rad. Transf. Mode": "Radiative transfer mode: 'Transmission' for primary transit observations (planet passing in front of star), 'Emission' for secondary eclipse observations (planet behind star).",
            "Night": "Observation date identifier (e.g., 2023-05-15). For high-resolution instruments, this creates a night-specific directory. For low-resolution instruments, this adds the instrument to the target without night specification."
        }

        # Help button for column2
        self.help_button_column2 = HelpButton(
            self.column2, 0, 0,
            "Add Night/Instrument Help",
            help_text_column2,
            columnspan=1
        )

        # Night field and button
        self.textfield_night = MyTextField(self.column2, 1, 1, "", "Night:", width=30)
        self.button_add_night = MyButton(
            self.column2, 1, 3, r'Add Night',
            bg="#1e4fda", color_panel=self.color, command=self.add_night, sticky="w"
        )

        # Column 3 Help Text
        help_text_column3 = {
            "Target": "Select the target to which the LR data will be added.",
            "LR Instrument": "Select the low-resolution instrument. Only LR instruments from the database are shown.",
            "Path to TBL file": "Full path to the .tbl file containing the spectroscopic data. The filename should follow the format: *_<pipeline>_<filter>.tbl (e.g., spectrum_jwst_g395h.tbl). The pipeline and filter names will be extracted from the filename. You can type the path manually or use the Browse button to select a file.",
            "Browse button": "Opens a file dialog to browse and select a TBL file. Once selected, the file path will be automatically inserted into the 'Path to TBL file' field.",
            "Min λ [μm]": "Minimum wavelength in micrometers for filtering the spectroscopic data. Data points below this wavelength will be excluded from the converted PKL file.",
            "Max λ [μm]": "Maximum wavelength in micrometers for filtering the spectroscopic data. Data points above this wavelength will be excluded from the converted PKL file.",
            "Depth Error Method": "Method to calculate depth errors from the TBL file. 'positive_error': uses only column 3 (positive error). 'mean': averages column 3 and absolute value of column 4 element-wise. 'max': takes maximum of column 3 and absolute value of column 4 element-wise.",
            "Convert TBL to PKL": "Converts the TBL file to PKL format for use in LR retrievals. The file will be saved as lr_data.pkl in the target's LR_Instruments directory. The conversion applies wavelength filtering based on Min λ and Max λ values."
        }

        # Help button for column3
        self.help_button_column3 = HelpButton(
            self.column3, 0, 0,
            "TBL to PKL Conversion Help",
            help_text_column3,
            columnspan=1
        )

        # Dropdown menus for TBL conversion
        self.dropdown_tbl_target = MyDropdown(
            self.column3, 0, 1, self.target_list, "Target:", color=self.color, columnspan=2
        )
        self.dropdown_tbl_lr_instruments = MyDropdown(
            self.column3, 0, 3, self.list_lr_instruments, "LR Instrument:", color=self.color,
            columnspan=2
        )
        self.dropdown_tbl_rad_mode = MyDropdown(
            self.column3, 0, 5, ConstantVariables.LIST_RAD_MODE,
            "Rad. Transf. Mode:", initial_value=0,
            color=self.color, columnspan=2
        )

        # Text field for TBL file path (increased width)
        self.textfield_tbl_path = MyTextField(
            self.column3, 1, 1, "", "Path to TBL file:", width=60, columnspan=6
        )

        # Browse button for TBL file selection
        self.button_browse_tbl = MyButton(
            self.column3, 1, 7, 'Browse',
            bg="#4CAF50", color_panel=self.color, command=self.browse_tbl_file,
            sticky="w", width=10
        )

        # Get default wavelength range from first LR instrument
        default_wl_min = "0"
        default_wl_max = "9999"
        if self.list_lr_instruments and self.list_lr_instruments[0] != "None":
            try:
                DB = DBSQLite3(self.path_default)
                instrument_obj = DB.get_instrument_by_key(self.list_lr_instruments[0])
                DB.close_DB()
                if instrument_obj and instrument_obj.wl_min and instrument_obj.wl_max:
                    default_wl_min = str(instrument_obj.wl_min)
                    default_wl_max = str(instrument_obj.wl_max)
            except Exception as e:
                print(f"Could not get default wavelength range: {e}")

        # Wavelength range controls (row 2) - auto-populate from instrument
        self.entry_wl_min = MyEntry(
            self.column3, 2, 1, default_wl_min, color=self.color, label_text=r'Min λ [μm]:',
            entry_width=10, columnspan=2
        )
        self.entry_wl_max = MyEntry(
            self.column3, 2, 3, default_wl_max, color=self.color, label_text=r'Max λ [μm]:',
            entry_width=10, columnspan=2
        )

        # Depth error method dropdown
        self.depth_error_methods = ["positive_error", "mean", "max", "min"]
        self.dropdown_depth_error_method = MyDropdown(
            self.column3, 2, 5,
            self.depth_error_methods,
            "Depth Error Method:",
            color=self.color,
            columnspan=2
        )

        self.entry_coeff_bandwidth = MyEntry(
            self.column3, 2, 7, "2", color=self.color, label_text='Bandwidth\ncoefficient:',
            entry_width=10, columnspan=2
        )

        # Set callback to update wavelength range when LR instrument is selected
        self.dropdown_tbl_lr_instruments.chosen_var.trace(
            "w", lambda *args: self.update_wl_range_from_instrument()
        )
        # Button to convert TBL to PKL (larger size, moved to row 3)
        self.button_convert_tbl = MyButton(
            self.column3, 3, 2, r'Convert TBL to PKL',
            bg="#1e4fda", color_panel=self.color, command=self.convert_tbl_to_pkl,
            columnspan=3, sticky="ew", width="35"
        )

    def add_target(self):
        """Add a new target to the database with all its parameters."""
        try:
            # Get input values
            target = self.textfield_target.get_text()
            radius_pl_jup = float(self.entry_radius.get_value())
            mass_pl_jup = float(self.entry_mass.get_value())
            T_eq = float(self.entry_teq.get_value())
            radius_st_sun = float(self.entry_stellar_radius.get_value())
            mass_st_sun = float(self.entry_stellar_mass.get_value())
            hjd0 = float(self.entry_hjd0.get_value())
            period = float(self.entry_period.get_value())
            vsys = float(self.entry_vsys.get_value())
            ecc = float(self.entry_ecc.get_value())
            opi = float(self.entry_opi.get_value())
            stellar_teff = float(self.entry_stellar_teff.get_value())
            ra = float(self.entry_ra.get_value())
            dec = float(self.entry_dec.get_value())
            a_Rs_ratio = float(self.entry_a_Rs_ratio.get_value())
            projected_obliquity = float(self.entry_projected_obliquity.get_value())
            inclination = float(self.entry_inclination.get_value())
            v_sini = float(self.entry_v_sini.get_value())

            # Calculate derived parameters
            Msun = phys_const.m_sun / 1e3
            MJ = phys_const.m_jup / 1e3
            G = phys_const.G / 1e3

            mass_pl_jup_min = mass_pl_jup * np.sin(np.deg2rad(inclination))
            
            # Calculate Keplerian parameters
            ks = (((2 * np.pi * G) ** (1 / 3) * mass_pl_jup_min * MJ) / (
                (86400 * period) ** (1 / 3) * (mass_st_sun * Msun + mass_pl_jup_min * MJ) ** (2 / 3)
            )) / 1e3
            kp = ((mass_st_sun * Msun * ks) / (mass_pl_jup_min * MJ))
            
            # Calculate gravity and limb parameters
            gravity = phys_const.G * (mass_pl_jup * phys_const.m_jup) / np.power(radius_pl_jup * phys_const.r_jup, 2)
            phase_dict = compute_transit_durations(
                period, a_Rs_ratio, (radius_pl_jup * ConstantVariables.R_JUP_MEAN) / (radius_st_sun * ConstantVariables.R_SUN),
                float(inclination), ecc=float(ecc), omega=float(opi)
            )
            limph_T14 = phase_dict["limph_T14"]
            limph_T12 = phase_dict["limph_T12"]
            limph_T23 = phase_dict["limph_T23"]
            t14_hours = phase_dict["T14_hours"]
            t12_hours = phase_dict["T12_hours"]
            t23_hours = phase_dict["T23_hours"]

            # Insert target into database
            DataInterface.insert_target_catalog(
                path_target=self.path_folder_targets,
                target_id=target,
                radius=str(radius_pl_jup),
                mass=str(mass_pl_jup),
                gravity=str(gravity),
                t_eq=str(T_eq),
                stellar_radius=str(radius_st_sun),
                stellar_mass=str(mass_st_sun),
                p0=str(-1),
                hjd0=str(hjd0),
                period=str(period),
                vsys=str(vsys),
                limph_T14=str(limph_T14),
                limph_T12=str(limph_T12),
                limph_T23=str(limph_T23),
                kp=str(kp),
                ks=str(ks),
                ecc=str(ecc),
                t14=str(t14_hours),
                t12=str(t12_hours),
                t23=str(t23_hours),
                opi=str(opi),
                stellar_teff=str(stellar_teff),
                ra=str(ra),
                dec=str(dec),
                a_Rs_ratio=str(a_Rs_ratio),
                projected_obliquity=str(projected_obliquity),
                inclination=str(inclination),
                v_sini=str(v_sini)
            )

            # Update UI components
            self._update_after_target_add()
            messagebox.showinfo("Add Target to DB", "Correctly added")

        except Exception as e:
            print(e)
            messagebox.showerror("Add Target to DB", "Not added")

    def _update_after_target_add(self):
        """Update UI components after adding a new target."""
        target_list = get_target_list(self.path_folder_targets)
        self.modify_list_target(target_list)

        # Update target lists in related frames
        self.frame_input.frame_parameter.panel_info.modify_target_list(self.target_list)
        self.frame_input.frame_tell_rem.modify_target_list(self.target_list)
        self.frame_input.frame_manual_model.modify_target_list(self.target_list)
        self.frame_input.frame_cc_night.modify_target_list(self.target_list)
        self.frame_input.frame_simulation_HR.modify_target_list(self.target_list)
        self.frame_input.frame_retrieval_analysis.frame_filter_table.frame_filter.modify_target_list(self.target_list)

    def add_night(self):
        """Add a new night or instrument to the target."""
        try:
            instrument = self.dropdown_instruments.get_value()
            target = self.dropdown_target.get_value()
            night = self.textfield_night.get_text()

            # Get instrument details from database
            DB = DBSQLite3(self.path_default)
            instrument_obj = DB.get_instrument_by_key(instrument)
            DB.close_DB()

            insert_night_in_target(
                self.path_folder_targets, target,
                self.dropdown_rad_mode.get_value(),
                instrument_obj.name, night
            )

            messagebox.showinfo("Correctly added", "Correctly added")

        except Exception as e:
            print(e)
            messagebox.showerror("Add Night", "Not added")
    
    def modify_list_target(self, target_list):
        """Update the target list dropdown with new targets."""
        self.dropdown_target.clean_widget()
        self.dropdown_target = MyDropdown(
            self.column2, 0, 1, target_list, 
            "Target:", color=self.color, columnspan=2
        )
        self.target_list = target_list

    def modify_list_instrument(self, list_instrument):
        """Update the instruments dropdowns by re-fetching from the database."""
        # Get updated instrument list from database with resolutions
        DB = DBSQLite3(self.path_default)
        all_instruments, resolutions, _, _, _ = DB.get_instruments()
        DB.close_DB()

        # Filter for HR and LR instruments separately
        self.list_hr_instruments = []
        self.list_lr_instruments = []
        if all_instruments and resolutions:
            for inst, res in zip(all_instruments, resolutions):
                if res == "HR":
                    self.list_hr_instruments.append(inst)
                if res == "LR":
                    self.list_lr_instruments.append(inst)

        if not self.list_hr_instruments:
            self.list_hr_instruments = ["None"]
        if not self.list_lr_instruments:
            self.list_lr_instruments = ["None"]

        # Update HR instruments dropdown in column2
        self.dropdown_instruments.clean_widget()
        self.dropdown_instruments = MyDropdown(
            self.column2, 0, 3, self.list_hr_instruments, "Instrument:", color=self.color,
            columnspan=2
        )

        # Update LR instruments dropdown in column3
        self.dropdown_tbl_lr_instruments.clean_widget()
        self.dropdown_tbl_lr_instruments = MyDropdown(
            self.column3, 0, 3, self.list_lr_instruments, "LR Instrument:", color=self.color,
            columnspan=2
        )
        self.dropdown_tbl_lr_instruments.chosen_var.trace(
            "w", lambda *args: self.update_wl_range_from_instrument()
        )

    def update_wl_range_from_instrument(self):
        """Update wavelength range fields based on selected LR instrument."""
        instrument_name = self.dropdown_tbl_lr_instruments.get_value()

        if instrument_name and instrument_name != "None":
            try:
                # Get instrument details from database
                DB = DBSQLite3(self.path_default)
                instrument_obj = DB.get_instrument_by_key(instrument_name)
                DB.close_DB()

                if instrument_obj and instrument_obj.wl_min and instrument_obj.wl_max:
                    # Update the entry fields with instrument's wavelength range
                    self.entry_wl_min.set_value(str(instrument_obj.wl_min))
                    self.entry_wl_max.set_value(str(instrument_obj.wl_max))
                    print(f"Updated wavelength range for {instrument_name}: {instrument_obj.wl_min} - {instrument_obj.wl_max} μm")
                else:
                    # Set default values if instrument data is not available
                    self.entry_wl_min.set_value("0")
                    self.entry_wl_max.set_value("9999")
            except Exception as e:
                print(f"Error updating wavelength range: {e}")
                # Set default values on error
                self.entry_wl_min.set_value("0")
                self.entry_wl_max.set_value("9999")

    def browse_tbl_file(self):
        """Open a file dialog to browse and select a TBL file."""
        try:
            # Open file dialog to select TBL file
            file_path = filedialog.askopenfilename(
                title="Select TBL file",
                filetypes=[
                    ("TBL files", "*.tbl"),
                    ("All files", "*.*")
                ],
                initialdir=self.path_folder_targets
            )

            # If a file was selected, update the text field
            if file_path:
                self.textfield_tbl_path.insert_text(file_path)
                print(f"Selected TBL file: {file_path}")
        except Exception as e:
            print(f"Error browsing for TBL file: {e}")
            messagebox.showerror("Browse Error", f"Failed to open file browser:\n{str(e)}")

    def convert_tbl_to_pkl(self):
        """Convert TBL file to PKL format for LR analysis."""
        try:
            # Get selections from UI
            target = self.dropdown_tbl_target.get_value()
            instrument = self.dropdown_tbl_lr_instruments.get_value()
            rad_mode = self.dropdown_tbl_rad_mode.get_value()
            file_tbl = self.textfield_tbl_path.get_text()

            # Validate inputs
            if target == "None" or not target:
                messagebox.showerror("Error", "Please select a target")
                return
            if instrument == "None" or not instrument:
                messagebox.showerror("Error", "Please select an LR instrument")
                return
            if not file_tbl or not Path(file_tbl).exists():
                messagebox.showerror("Error", "Please provide a valid path to the TBL file")
                return

            # Read TBL file
            with open(file_tbl, 'r') as f:
                lines = f.readlines()

            # Remove metadata lines (starting with "\") and blank lines
            content = [line for line in lines if
                       not line.startswith('\\') and not line.startswith('|') and line.strip() != '']
            data_str = ''.join(content)

            # Extract filter and pipeline from filename
            split_name = file_tbl[:-4].split("_")
            filter_lr_m = split_name[-1]
            pipeline_m = split_name[-2]

            # Write cleaned data to temporary file
            temp_file = file_tbl[:-4] + "_cleaned.txt"
            with open(temp_file, 'w') as f:
                f.write(data_str)

            # Read cleaned data as CSV
            df = pd.read_csv(temp_file, header=None, sep=r'\s+')

            # Extract data columns
            central_wl_micron_m = np.array(df[0])
            bandwidth_micron_dr_m = np.array(df[1])
            transit_depth_spectr_m = np.array(df[2]) / 100

            # Handle NaN or null values in bandwidth column
            if np.any(np.isnan(bandwidth_micron_dr_m)) or bandwidth_micron_dr_m is None:
                print("Found NaN/null values in bandwidth column, calculating from central wavelength differences...")
                bandwidth_micron_dr_m = np.zeros_like(central_wl_micron_m)
                for i in range(len(bandwidth_micron_dr_m)):
                    if i == 0 and i < len(central_wl_micron_m) - 1:
                        # First element: use difference to next point divided by 2
                        bandwidth_micron_dr_m[i] = (central_wl_micron_m[i+1] - central_wl_micron_m[i]) / 2
                    elif i == len(central_wl_micron_m) - 1:
                        # Last element: use difference from previous point divided by 2
                        bandwidth_micron_dr_m[i] = (central_wl_micron_m[i] - central_wl_micron_m[i-1]) / 2
                    else:
                        # Middle elements: use half the difference between adjacent points
                        bandwidth_micron_dr_m[i] = (central_wl_micron_m[i+1] - central_wl_micron_m[i-1]) / 2
                print(f"Calculated bandwidths: {bandwidth_micron_dr_m}")
            else:
                bandwidth_micron_dr_m = bandwidth_micron_dr_m / int(self.entry_coeff_bandwidth.get_value())

            # Calculate error based on selected method
            error_method = self.dropdown_depth_error_method.get_value()
            if error_method == "positive_error":
                # Use only positive error (column 3)
                error_sigma_m = np.array(df[3]) / 100
            elif error_method == "mean":
                # Mean of positive error (column 3) and absolute value of negative error (column 4)
                error_positive = np.array(df[3])
                error_negative = np.abs(np.array(df[4]))
                error_sigma_m = (error_positive + error_negative) / 2 / 100
            elif error_method == "max":
                # Maximum of positive error (column 3) and absolute value of negative error (column 4)
                error_positive = np.array(df[3])
                error_negative = np.abs(np.array(df[4]))
                error_sigma_m = np.maximum(error_positive, error_negative) / 100
            elif error_method == "min":
                # Minimum of positive error (column 3) and absolute value of negative error (column 4)
                error_positive = np.array(df[3])
                error_negative = np.abs(np.array(df[4]))
                error_sigma_m = np.minimum(error_positive, error_negative) / 100
            else:
                # Default to positive_error
                error_sigma_m = np.array(df[3]) / 100

            print(f"Using depth error method: {error_method}")

            # Convert units: microns to nm
            central_wl_nm_m = central_wl_micron_m * 1000
            bandwidth_nm_dr_m = bandwidth_micron_dr_m * 1000


            # Calculate transit/eclipse depth (spectrum for retrieval)
            if rad_mode == "Transmission":
                ylabel = r"1 - Transit Depth $\left[1 - \left(\frac{R_P}{R_S}\right)^2\right]$"
                depth_lr = 1 - transit_depth_spectr_m
            else:
                ylabel = r"1 + Emission lines $\left[1 + \left(\frac{R_P}{R_S}\right)^2\right]$"
                depth_lr = 1 +  transit_depth_spectr_m


            # Apply wavelength range filtering
            try:
                wl_min = float(self.entry_wl_min.get_value())
                wl_max = float(self.entry_wl_max.get_value())

                # Create mask for wavelengths within the specified range (in microns)
                mask = (central_wl_micron_m >= wl_min) & (central_wl_micron_m <= wl_max)

                # Apply mask to all data arrays
                central_wl_nm_m = central_wl_nm_m[mask]
                bandwidth_nm_dr_m = bandwidth_nm_dr_m[mask]
                depth_lr = depth_lr[mask]
                error_sigma_m = error_sigma_m[mask]

                print(f"Wavelength range filtering applied: {wl_min} - {wl_max} μm. Data points after filtering: {len(central_wl_nm_m)}")
            except (ValueError, AttributeError) as e:
                print(f"Warning: Could not apply wavelength filtering: {e}. Proceeding with full dataset.")

            # Create lr_data dictionary
            lr_data = {
                "lr_lambd": central_wl_nm_m,
                "lr_lambdr": bandwidth_nm_dr_m,
                "lr_spectr": depth_lr,
                "lr_sigma": error_sigma_m,
            }

            output_dir = insert_instrument_lr_in_target(
                self.path_folder_targets, target, rad_mode, instrument
            )
            output_file_pkl = output_dir / "lr_data.pkl"
            output_file_png = output_dir / "lr_data.png"

            # Save the pkl file
            with open(str(output_file_pkl), "wb") as fo:
                pickle.dump(lr_data, fo)


            fig, axs = plt.subplots(1, 1, figsize=(12, 8), dpi=300)
            axs.errorbar(
                central_wl_nm_m, depth_lr,
                yerr=error_sigma_m, xerr=bandwidth_nm_dr_m,
                label=instrument, linestyle='None', marker='*', color="orange", alpha=0.5
            )
            axs.set_title(target)
            axs.set_ylabel(ylabel)
            axs.set_xlabel(r"Wavelength [nm]")
            axs.legend()
            plt.savefig(output_file_png, bbox_inches='tight')
            plt.close(fig)


            # Clean up temporary file
            Path(temp_file).unlink(missing_ok=True)

            messagebox.showinfo(
                "Success",
                f"Successfully converted TBL to PKL\n\nOutput file:\n{output_file_pkl}\n\n"
                f"Radiative Transfer Mode: {rad_mode}\n"
                f"Filter: {filter_lr_m}\nPipeline: {pipeline_m}\n"
                f"Number of data points: {len(central_wl_nm_m)}"
            )

        except Exception as e:
            import traceback
            error_msg = f"Error converting TBL to PKL:\n{str(e)}\n\n{traceback.format_exc()}"
            print(error_msg)
            messagebox.showerror("Conversion Error", f"Failed to convert TBL to PKL:\n{str(e)}")
