# FlightMonitor/gui/panels/selected_flight_details_panel.py
"""
Panel for displaying brief details of the currently selected flight
and a button to open the full flight details window.
"""
import tkinter as tk
from tkinter import ttk
from tkinter import font as tkFont # For font checking
from typing import Dict, Any, Optional
from datetime import datetime, timezone # For timestamp formatting

from flightmonitor.utils.logger import get_logger

module_logger = get_logger(__name__)


class SelectedFlightDetailsPanel:
    """
    Manages the GUI elements for displaying a selected flight's brief details.
    """

    def __init__(self, parent_frame: ttk.LabelFrame, controller: Any):
        """
        Initializes the SelectedFlightDetailsPanel.

        Args:
            parent_frame: The parent ttk.LabelFrame where this panel will be placed.
            controller: The application controller instance to delegate actions like
                        requesting full flight details.
        """
        self.parent_frame = parent_frame
        self.controller = controller
        self.flight_detail_labels: Dict[str, ttk.Label] = {}
        self._current_icao24_displayed: Optional[str] = None # To track which flight is currently shown

        # Configure columns for a two-column grid layout within the LabelFrame
        self.parent_frame.columnconfigure(1, weight=1) # First value column
        self.parent_frame.columnconfigure(3, weight=1) # Second value column

        self._create_widgets() # Call a helper method to build the UI elements
        module_logger.debug("SelectedFlightDetailsPanel initialized.")

    def _create_widgets(self):
        """
        Creates all the labels for flight details and the 'Full Details' button.
        """
        # Define fields for the two columns. Keys map to flight data dictionary keys.
        fields_col1 = [
            ("icao24", "ICAO24:"),
            ("baro_altitude_m", "Altitude (baro):"),
            ("velocity_mps", "Speed (GS):"),
            ("true_track_deg", "Track (°):"),
            ("squawk", "Squawk:"),
            ("position_source", "Pos. Source:"),
            ("registration", "Registration:"),
            ("model", "Model:"),
            ("operator", "Operator:"),
            ("categorydescription", "Category:"),
            ("serialnumber", "Serial No.:"),
            ("firstflightdate", "First Flight:"),
        ]
        fields_col2 = [
            ("callsign", "Callsign:"),
            ("geo_altitude_m", "Altitude (Geo):"),
            ("vertical_rate_mps", "Vert. Rate:"),
            ("on_ground", "On Ground:"),
            ("spi", "SPI:"),
            ("origin_country", "Origin Country:"),
            ("manufacturername", "Manufacturer:"),
            ("typecode", "Type Code:"),
            ("operatorcallsign", "Op. Callsign:"),
            ("built_year", "Built Year:"),
            ("country", "Country (Reg):"),
            ("timestamp_metadata", "DB Timestamp:"),
        ]

        # Determine the maximum number of rows needed for the grid
        max_rows = max(len(fields_col1), len(fields_col2))

        # Populate the grid with labels for keys and values
        for i in range(max_rows):
            # Column 1 fields
            if i < len(fields_col1):
                key1, label_text1 = fields_col1[i]
                # Label for the field name (e.g., "ICAO24:")
                ttk.Label(
                    self.parent_frame,
                    text=label_text1,
                    font="-weight bold" if key1 == "icao24" else None, # Make ICAO24 bold
                ).grid(row=i, column=0, sticky=tk.W, pady=0, padx=(0, 2))
                # Label for the value (will be updated dynamically)
                value_label1 = ttk.Label(self.parent_frame, text="N/A", wraplength=130)
                value_label1.grid(row=i, column=1, sticky=tk.W, pady=0, padx=(0, 10))
                self.flight_detail_labels[key1] = value_label1 # Store reference to value label

            # Column 2 fields
            if i < len(fields_col2):
                key2, label_text2 = fields_col2[i]
                # Label for the field name
                ttk.Label(self.parent_frame, text=label_text2).grid(
                    row=i, column=2, sticky=tk.W, pady=0, padx=(5, 2)
                )
                # Label for the value
                value_label2 = ttk.Label(self.parent_frame, text="N/A", wraplength=130)
                value_label2.grid(row=i, column=3, sticky=tk.W, pady=0, padx=(0, 0))
                self.flight_detail_labels[key2] = value_label2 # Store reference

        # Button to show full flight details
        self.full_details_button = ttk.Button(
            self.parent_frame,
            text="Aircraft Full Details...",
            command=self._on_show_full_details_button, # Bind to internal method
            state=tk.DISABLED, # Initially disabled until a flight is selected
        )
        self.full_details_button.grid(
            row=max_rows, column=0, columnspan=4, pady=(10, 0), sticky="ew"
        )

    def update_details(self, flight_data: Optional[Dict[str, Any]]):
        """
        Updates the displayed flight details based on the provided data.

        Args:
            flight_data: A dictionary containing flight information (e.g., from CanonicalFlightState.to_dict()).
                         If None, all fields will be reset to "N/A".
        """
        # Reset current ICAO tracker
        self._current_icao24_displayed = None
        module_logger.debug(
            f"SelectedFlightDetailsPanel: Updating details for: {flight_data.get('icao24', 'None') if flight_data else 'None'}"
        )

        # Clear all labels first
        for label_widget in self.flight_detail_labels.values():
            if label_widget.winfo_exists(): # Check if widget is still valid
                label_widget.config(text="N/A")

        if flight_data:
            # Handle special formatting for altitude fields as they can show baro or geo
            baro_alt_val = flight_data.get("baro_altitude_m")
            geo_alt_val = flight_data.get("geo_altitude_m")

            if (
                "baro_altitude_m" in self.flight_detail_labels
                and self.flight_detail_labels["baro_altitude_m"].winfo_exists()
            ):
                alt_text = "N/A"
                if baro_alt_val is not None:
                    alt_text = f"{baro_alt_val:.0f} m"
                elif geo_alt_val is not None: # Fallback to geo if baro is N/A
                    alt_text = f"{geo_alt_val:.0f} m (geo)"
                self.flight_detail_labels["baro_altitude_m"].config(text=alt_text)

            if (
                "geo_altitude_m" in self.flight_detail_labels
                and self.flight_detail_labels["geo_altitude_m"].winfo_exists()
            ):
                alt_geo_text = "N/A"
                if geo_alt_val is not None:
                    alt_geo_text = f"{geo_alt_val:.0f} m"
                # Show geo_altitude only if it's significantly different from baro, or if baro is N/A
                if (
                    baro_alt_val is not None
                    and geo_alt_val is not None
                    and abs(baro_alt_val - geo_alt_val) > 1 # Arbitrary threshold for "significant difference"
                ) or (baro_alt_val is None and geo_alt_val is not None):
                    self.flight_detail_labels["geo_altitude_m"].config(text=alt_geo_text)
                # Else, if geo is similar to baro or geo is also N/A, leave geo_altitude_m as "N/A" (default clear state)

            # Iterate over all other defined labels and update their text
            for key, label_widget in self.flight_detail_labels.items():
                # Skip altitude fields as they are handled above
                if key in ["baro_altitude_m", "geo_altitude_m"]:
                    continue

                if label_widget.winfo_exists():
                    value = flight_data.get(key)
                    formatted_value = "N/A"
                    if value is not None and str(value).strip() != "":
                        # Apply specific formatting based on key
                        if key == "velocity_mps" and isinstance(value, (float, int)):
                            formatted_value = f"{value:.1f} m/s ({value * 1.94384:.1f} kts)"
                        elif key == "vertical_rate_mps" and isinstance(value, (float, int)):
                            formatted_value = f"{value * 196.85:.0f} ft/min ({value:.1f} m/s)"
                        elif key == "true_track_deg" and isinstance(value, (float, int)):
                            formatted_value = f"{value:.1f}°"
                        elif key in [
                            "timestamp", "last_contact_timestamp", "timestamp_metadata"
                        ]:
                            # These are timestamps (float epoch seconds)
                            if isinstance(value, (int, float)) and value > 0:
                                try:
                                    formatted_value = datetime.fromtimestamp(value, tz=timezone.utc).strftime("%Y-%m-%d %H:%M:%S Z")
                                except: # Fallback if timestamp conversion fails
                                    formatted_value = str(value) + " (raw ts)"
                            elif isinstance(value, str) and value.strip(): # Already a string (e.g., from DB)
                                formatted_value = value
                        elif key == "firstflightdate":
                            # This could be a timestamp or a string date
                            if isinstance(value, (int, float)) and value > 0:
                                try:
                                    formatted_value = datetime.fromtimestamp(value, tz=timezone.utc).strftime('%Y-%m-%d')
                                except:
                                    formatted_value = str(value)
                            elif isinstance(value, str) and value.strip():
                                formatted_value = value
                        elif isinstance(value, bool):
                            formatted_value = str(value) # "True" or "False"
                        elif key == "built_year" and value: # Ensure built_year without decimals
                            formatted_value = str(int(value)) if isinstance(value, (float, int)) and value > 0 else str(value)
                        else:
                            formatted_value = str(value) # Default to string conversion
                    label_widget.config(text=formatted_value)
            
            # Store the ICAO24 of the flight currently displayed, for the full details button
            self._current_icao24_displayed = flight_data.get("icao24")

            # Enable the "Full Details" button if a valid ICAO24 is present
            if self.full_details_button.winfo_exists():
                self.full_details_button.config(state=tk.NORMAL if self._current_icao24_displayed else tk.DISABLED)
        else: # No flight_data, so disable button
            if self.full_details_button.winfo_exists():
                self.full_details_button.config(state=tk.DISABLED)
        module_logger.debug("Selected flight details panel updated.")

    def _on_show_full_details_button(self):
        """
        Callback method for the 'Aircraft Full Details...' button.
        Requests the application controller to open the full details window for the
        currently displayed flight (if any).
        """
        if self._current_icao24_displayed:
            if self.controller and hasattr(self.controller, "request_and_show_full_flight_details"):
                module_logger.info(f"SelectedFlightDetailsPanel: Requesting full details for ICAO: {self._current_icao24_displayed}")
                self.controller.request_and_show_full_flight_details(self._current_icao24_displayed)
            else:
                module_logger.error("SelectedFlightDetailsPanel: Controller or method 'request_and_show_full_flight_details' not available.")
                self._show_error_message(
                    "Error", "Cannot open full details window (controller issue)."
                )
        else:
            self._show_info_message(
                "No Flight Selected",
                "Please select a flight on the map first to see full details."
            )
            module_logger.warning("SelectedFlightDetailsPanel: Full details button clicked, but no flight ICAO available.")

    def _show_error_message(self, title: str, message: str):
        """
        Helper method to show an error message, delegating to MainWindow via controller.
        """
        if self.controller and hasattr(self.controller, "main_window") and self.controller.main_window:
            main_window = self.controller.main_window
            if hasattr(main_window, "show_error_message"):
                main_window.show_error_message(title, message)
            else:
                module_logger.error(f"MainWindow.show_error_message not found. Error: {title} - {message}")
        else:
            module_logger.error(f"Controller or MainWindow not available to show error: {title} - {message}")

    def _show_info_message(self, title: str, message: str):
        """
        Helper method to show an info message, delegating to MainWindow via controller.
        """
        if self.controller and hasattr(self.controller, "main_window") and self.controller.main_window:
            main_window = self.controller.main_window
            if hasattr(main_window, "show_info_message"):
                main_window.show_info_message(title, message)
            else:
                module_logger.warning(f"MainWindow.show_info_message not found. Info: {title} - {message}")
        else:
            module_logger.warning(f"Controller or MainWindow not available to show info: {title} - {message}")