# FlightMonitor/gui/dialogs/full_flight_details_window.py
import tkinter as tk
from tkinter import ttk
import webbrowser
from datetime import datetime, timezone
from typing import Optional, Dict, Any, List, Tuple
import time

# Assumendo che MapCanvasManager e le utility siano nei percorsi corretti
# Se questi import falliscono, MapCanvasManager non sarà disponibile
try:
    from flightmonitor.map.map_canvas_manager import MapCanvasManager
    MAP_MANAGER_AVAILABLE = True
except ImportError:
    MapCanvasManager = None # type: ignore
    MAP_MANAGER_AVAILABLE = False

from flightmonitor.map.map_utils import _is_valid_bbox_dict, _is_valid_bbox_dict # Usato per validare BBox
from flightmonitor.data.common_models import CanonicalFlightState
from collections import deque

try:
    from flightmonitor.utils.logger import get_logger
    logger = get_logger(__name__)
except ImportError:
    import logging
    logger = logging.getLogger(__name__)
    if not logger.hasHandlers(): # Configurazione di base se il logger dell'app non è disponibile
        logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s: %(message)s")
    logger.warning("FullFlightDetailsWindow using fallback standard Python logger.")

DEFAULT_SINGLE_POINT_PATCH_KM = 20.0


class FullFlightDetailsWindow(tk.Toplevel):
    def __init__(self, parent, icao24: str, controller: Optional[Any] = None):
        super().__init__(parent)
        
        self.icao24 = icao24.lower().strip() 
        self.title(f"Full Details - {self.icao24.upper()}")

        self.parent = parent
        self.controller = controller

        self._initial_static_data: Optional[Dict[str, Any]] = None
        self._initial_live_data: Optional[Dict[str, Any]] = None
        self._initial_track_data: Optional[List[Dict[str, Any]]] = None

        self.geometry("1100x700") 
        self.minsize(850, 550)   

        self.main_h_pane = ttk.PanedWindow(self, orient=tk.HORIZONTAL)
        self.main_h_pane.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # --- Colonna Sinistra (Info testuali e Immagine) ---
        left_column_frame = ttk.Frame(self.main_h_pane, padding=5)
        self.main_h_pane.add(left_column_frame, weight=4) # 40% circa

        static_details_container = ttk.LabelFrame(left_column_frame, text=f"Aircraft Information ({self.icao24.upper()})", padding=10)
        static_details_container.pack(fill=tk.X, expand=False, pady=(0,10), anchor='n')

        self.detail_labels: Dict[str, ttk.Label] = {} 
        self._create_details_layout(static_details_container) 

        image_link_container = ttk.Frame(left_column_frame, padding=(0,5,0,10)) 
        image_link_container.pack(fill=tk.X, expand=False, pady=(5,10), anchor='n')
        self.image_placeholder_label = ttk.Label(image_link_container, text="[ Aircraft Image Area ]", relief="groove", anchor="center", borderwidth=2, padding=10, takefocus=False)
        # Per dare una dimensione minima al placeholder dell'immagine
        #self.image_placeholder_label.configure(height=8) # Altezza in linee di testo, aggiusta se necessario
        self.image_placeholder_label.pack(fill=tk.X, expand=False, pady=(0,5)) 
        
        self.jetphotos_link_label = ttk.Label(image_link_container, text="View on JetPhotos", foreground="blue", cursor="hand2", anchor="center")
        self.jetphotos_link_label.pack(fill=tk.X)
        self.jetphotos_link_label.bind("<Button-1>", self._open_jetphotos_link_action)
        self.current_jetphotos_url: Optional[str] = None
        self.jetphotos_link_label.pack_forget()

        live_data_container = ttk.LabelFrame(left_column_frame, text="Current Flight Status", padding=10)
        live_data_container.pack(fill=tk.X, expand=False, pady=(10,0), anchor='n') 
        self._create_live_details_layout(live_data_container)


        # --- Colonna Destra (Notebook con Mappa e Tabella) ---
        right_column_frame = ttk.Frame(self.main_h_pane, padding=5)
        self.main_h_pane.add(right_column_frame, weight=6) # 60% circa

        self.track_notebook = ttk.Notebook(right_column_frame)
        self.track_notebook.pack(fill=tk.BOTH, expand=True)
        
        self.track_map_tab = ttk.Frame(self.track_notebook)
        self.track_notebook.add(self.track_map_tab, text="Flight Track Map")
        self.track_map_canvas = tk.Canvas(self.track_map_tab, bg="gray70", highlightthickness=0)
        self.track_map_canvas.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
        self.detail_map_manager: Optional[MapCanvasManager] = None
        self._map_init_error_displayed = False

        self.track_table_tab = ttk.Frame(self.track_notebook)
        self.track_notebook.add(self.track_table_tab, text="Track Data Table")
        table_frame = ttk.Frame(self.track_table_tab)
        table_frame.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)

        self.track_table_cols = {
            "timestamp": {"text": "Timestamp (UTC)", "width": 150, "anchor": tk.W},
            "latitude": {"text": "Latitude", "width": 90, "anchor": tk.E},
            "longitude": {"text": "Longitude", "width": 90, "anchor": tk.E},
            "baro_altitude_m": {"text": "Alt.(Baro) m", "width": 80, "anchor": tk.E},
            "geo_altitude_m": {"text": "Alt.(Geo) m", "width": 80, "anchor": tk.E},
            "velocity_mps": {"text": "Speed m/s", "width": 80, "anchor": tk.E},
            "true_track_deg": {"text": "Track °", "width": 60, "anchor": tk.E},
            "vertical_rate_mps": {"text": "V.Rate m/s", "width": 80, "anchor": tk.E},
            "on_ground": {"text": "On Ground", "width": 70, "anchor": tk.CENTER},
        }
        self.track_table = ttk.Treeview(
            table_frame,
            columns=list(self.track_table_cols.keys()),
            show="headings",
            selectmode="browse"
        )
        for col_key, col_props in self.track_table_cols.items():
            self.track_table.heading(col_key, text=col_props["text"], anchor=col_props.get("heading_anchor", tk.CENTER))
            self.track_table.column(col_key, width=col_props["width"], anchor=col_props["anchor"], stretch=tk.YES)

        vsb = ttk.Scrollbar(table_frame, orient="vertical", command=self.track_table.yview)
        vsb.pack(side=tk.RIGHT, fill=tk.Y)
        hsb = ttk.Scrollbar(table_frame, orient="horizontal", command=self.track_table.xview)
        hsb.pack(side=tk.BOTTOM, fill=tk.X)
        self.track_table.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
        self.track_table.pack(fill=tk.BOTH, expand=True)

        self.center_window()
        self.focus_set()

        self.after(100, self._initialize_detail_map_manager)
        self.protocol("WM_DELETE_WINDOW", self._on_closing_details_window)
        
        # Imposta la posizione del sash dopo un breve ritardo
        self.after(50, self._set_initial_sashpos)


    def _set_initial_sashpos(self):
        if self.winfo_exists() and self.main_h_pane.winfo_exists():
            try:
                self.update_idletasks() 
                total_width = self.main_h_pane.winfo_width()
                
                if total_width > 100: 
                    desired_left_pane_width = int(total_width * 0.40) # 40%
                    self.main_h_pane.sashpos(0, desired_left_pane_width)
                    logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Sash position set for left pane to: {desired_left_pane_width} (40% of {total_width})")
                else:
                    logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): PanedWindow width ({total_width}) not ready for sashpos, retrying.")
                    self.after(100, self._set_initial_sashpos)
            except tk.TclError as e:
                logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): TclError setting sash position: {e}. Will retry if window still exists.")
                if self.winfo_exists(): 
                    self.after(150, self._set_initial_sashpos)
            except Exception as e_sash:
                logger.error(f"FullDetailsWindow ({self.icao24.upper()}): Unexpected error setting sash position: {e_sash}", exc_info=True)
        else:
            logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): Window or PanedWindow destroyed before sashpos could be set.")

    def _initialize_detail_map_manager(self):
        if not MAP_MANAGER_AVAILABLE: # Controlla se MapCanvasManager è stato importato
            logger.error(f"FullDetailsWindow ({self.icao24.upper()}): MapCanvasManager not available. Cannot initialize detail map.")
            if self.track_map_canvas.winfo_exists() and not self._map_init_error_displayed:
                 self.track_map_canvas.create_text(
                    self.track_map_canvas.winfo_width() / 2, self.track_map_canvas.winfo_height() / 2,
                    text="Map functionality is unavailable\n(Import Error)",
                    fill="orange", font=("Arial", 10), justify=tk.CENTER
                )
                 self._map_init_error_displayed = True
            return

        if not self.track_map_canvas.winfo_exists():
            logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): Detail map canvas does not exist. Cannot initialize MapCanvasManager.")
            return

        canvas_w = self.track_map_canvas.winfo_width()
        canvas_h = self.track_map_canvas.winfo_height()

        if canvas_w <= 1 or canvas_h <= 1:
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Detail map canvas not yet sized. Retrying initialization later.")
            self.after(200, self._initialize_detail_map_manager)
            return

        logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Initializing MapCanvasManager for detail window (Canvas size: {canvas_w}x{canvas_h})")
        try:
            self.detail_map_manager = MapCanvasManager(
                app_controller=self.controller,
                tk_canvas=self.track_map_canvas,
                initial_bbox_dict=None,
                is_detail_map=True 
            )
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): MapCanvasManager for detail window initialized.")

            if self._initial_track_data is not None or self._initial_live_data is not None:
                logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Map manager ready, applying initial track/live data to map.")
                self._update_track_map(self._initial_track_data, self._initial_live_data)
            else:
                if self.detail_map_manager: # Assicura che sia stato creato
                    self.detail_map_manager._display_placeholder_text("Awaiting flight data...")

        except Exception as e:
            logger.error(f"FullDetailsWindow ({self.icao24.upper()}): Failed to initialize MapCanvasManager for detail window: {e}", exc_info=True)
            if self.track_map_canvas.winfo_exists() and not self._map_init_error_displayed:
                 self.track_map_canvas.create_text(
                    canvas_w / 2, canvas_h / 2,
                    text=f"Error initializing map:\n{e}",
                    fill="red", font=("Arial", 10), justify=tk.CENTER
                )
                 self._map_init_error_displayed = True

    def _create_details_layout(self, parent_frame: ttk.LabelFrame):
        parent_frame.columnconfigure(1, weight=1) 
        parent_frame.columnconfigure(3, weight=1) 

        fields_static = [
            ("icao24", "ICAO24:"), ("registration", "Registration:"), 
            ("manufacturername", "Manufacturer:"), ("model", "Model:"), 
            ("typecode", "Type Code:"), ("serialnumber", "Serial No.:"),
            ("operator", "Operator:"), ("operatorcallsign", "Op. Callsign:"), 
            ("operatoricao", "Op. ICAO:"), ("operatoriata", "Op. IATA:"), 
            ("country", "Country (Reg):"), ("categorydescription", "Category:"),
            ("built_year", "Built Year:"), ("engines", "Engines:"), 
            ("icaoclass", "ICAO Class:"), ("linenumber", "Line No.:"), 
            ("owner", "Owner:"), ("notes", "Notes:"), 
            ("status", "Status (DB):"), ("firstflightdate", "First Flight:"), 
            ("timestamp_metadata", "DB Record Time:")
        ]
        
        row_idx = 0
        col_idx = 0 
        for key, text_label in fields_static:
            lbl = ttk.Label(parent_frame, text=text_label, font="-weight bold" if key == "icao24" else None)
            lbl.grid(row=row_idx, column=col_idx * 2, sticky=tk.W, pady=1, padx=(0 if col_idx == 0 else 10, 3))
            
            val_lbl = ttk.Label(parent_frame, text="N/A", wraplength=150) 
            val_lbl.grid(row=row_idx, column=col_idx * 2 + 1, sticky=tk.W, pady=1, padx=(0, 5))
            self.detail_labels[key] = val_lbl
            
            if col_idx == 0: 
                col_idx = 1
            else: 
                col_idx = 0
                row_idx += 1
        
        if col_idx == 1: # If odd number of fields, last one is in first col
             ttk.Frame(parent_frame).grid(row=row_idx, column=2, columnspan=2) # Dummy to push next section down if needed


    def _create_live_details_layout(self, parent_frame: ttk.LabelFrame):
        parent_frame.columnconfigure(1, weight=1)
        parent_frame.columnconfigure(3, weight=1)

        live_fields = [
            ("callsign", "Callsign (Live):"), ("origin_country", "Origin Country (Live):"),
            ("baro_altitude_m", "Altitude (Baro):"), ("geo_altitude_m", "Altitude (Geo):"),
            ("velocity_mps", "Speed (GS):"), ("vertical_rate_mps", "Vertical Rate:"),
            ("true_track_deg", "Track (°):"), ("on_ground", "On Ground:"),
            ("squawk", "Squawk:"), ("spi", "SPI:"),
            ("position_source", "Position Source:"), 
            ("timestamp", "Last Position Time:"), ("last_contact_timestamp", "Last Contact Time:")
        ]
        row_idx = 0
        col_idx = 0
        for key, text_label in live_fields:
            lbl = ttk.Label(parent_frame, text=text_label)
            lbl.grid(row=row_idx, column=col_idx * 2, sticky=tk.W, pady=1, padx=(0 if col_idx == 0 else 10, 3))
            val_lbl = ttk.Label(parent_frame, text="N/A", wraplength=150)
            val_lbl.grid(row=row_idx, column=col_idx * 2 + 1, sticky=tk.W, pady=1, padx=(0, 5))
            self.detail_labels[key] = val_lbl
            
            if col_idx == 0: col_idx = 1
            else: col_idx = 0; row_idx += 1
        if col_idx == 1: # If odd number of fields
             ttk.Frame(parent_frame).grid(row=row_idx, column=2, columnspan=2)

    def update_details(
        self,
        static_data: Optional[Dict[str, Any]],
        live_data: Optional[Dict[str, Any]],
        full_track_data: Optional[List[Dict[str, Any]]],
    ):
        if not self.winfo_exists(): return

        self._initial_static_data = static_data
        self._initial_live_data = live_data
        self._initial_track_data = full_track_data

        logger.debug(f"FullDetailsWindow ({self.icao24.upper()}): Updating. Static: {bool(static_data)}, Live: {bool(live_data)}, Track points: {len(full_track_data) if full_track_data else 0}")

        all_data = {}
        if static_data: all_data.update(static_data)
        if live_data:
            if 'icao24' in live_data and isinstance(live_data['icao24'], str):
                live_data_processed = live_data.copy()
                live_data_processed['icao24'] = live_data_processed['icao24'].lower().strip()
                all_data.update(live_data_processed)
            else:
                all_data.update(live_data)

        for key, label_widget in self.detail_labels.items():
            if label_widget.winfo_exists():
                value = all_data.get(key)
                if key == "icao24":
                    display_text = self.icao24.upper() if self.icao24 else "N/A"
                else:
                    display_text = "N/A"
                    if value is not None and not (isinstance(value, str) and not value.strip()):
                        if key in ["baro_altitude_m", "geo_altitude_m"] and isinstance(value, (float, int)): display_text = f"{value:.0f} m"
                        elif key == "velocity_mps" and isinstance(value, (float, int)): display_text = f"{value:.1f} m/s  ({value * 1.94384:.1f} kts)"
                        elif key == "vertical_rate_mps" and isinstance(value, (float, int)): display_text = f"{value * 196.85:.0f} ft/min  ({value:.1f} m/s)"
                        elif key == "true_track_deg" and isinstance(value, (float, int)): display_text = f"{value:.1f}°"
                        elif key in ["timestamp", "last_contact_timestamp", "timestamp_metadata"]:
                            if isinstance(value, (int, float)) and value > 0:
                                try: display_text = datetime.fromtimestamp(value, tz=timezone.utc).strftime('%Y-%m-%d %H:%M:%S Z')
                                except: display_text = str(value) + " (raw ts)"
                            elif isinstance(value, str) and value.strip(): display_text = value
                        elif key == "firstflightdate":
                             if isinstance(value, str) and value.strip(): display_text = value
                             elif isinstance(value, (int,float)) and value > 0 :
                                try: display_text = datetime.fromtimestamp(value, tz=timezone.utc).strftime('%Y-%m-%d')
                                except: display_text = str(value)
                        elif isinstance(value, bool): display_text = str(value)
                        elif key == "built_year" and value: display_text = str(int(value)) if isinstance(value, (float, int)) and value > 0 else str(value)
                        else: display_text = str(value)
                label_widget.config(text=display_text)

        registration = all_data.get("registration")
        if registration and str(registration).strip() and str(registration) != "N/A":
            self.current_jetphotos_url = f"https://www.jetphotos.com/photo/keyword/{str(registration).upper()}"
            self.jetphotos_link_label.config(text=f"View '{str(registration).upper()}' on JetPhotos")
            if not self.jetphotos_link_label.winfo_ismapped(): self.jetphotos_link_label.pack(fill=tk.X)
        else:
            self.current_jetphotos_url = None
            if self.jetphotos_link_label.winfo_ismapped(): self.jetphotos_link_label.pack_forget()

        self._update_track_table(full_track_data)
        if self.detail_map_manager and self.detail_map_manager.canvas.winfo_exists():
            self._update_track_map(full_track_data, live_data)
        else:
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): update_details called, but detail_map_manager not ready. Map will update upon manager initialization.")

    def _update_track_table(self, track_data_list: Optional[List[Dict[str, Any]]]):
        if not self.track_table.winfo_exists(): return
        for item in self.track_table.get_children(): self.track_table.delete(item)

        if not track_data_list:
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): No track data to display in table.")
            return

        logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Populating track table with {len(track_data_list)} points.")
        for point_dict in reversed(track_data_list):
            values = []
            for col_key in self.track_table_cols.keys():
                raw_value = point_dict.get(col_key)
                display_value = "N/A"
                if raw_value is not None:
                    if col_key == "timestamp":
                        try: display_value = datetime.fromtimestamp(float(raw_value), tz=timezone.utc).strftime('%H:%M:%S')
                        except: display_value = str(raw_value)
                    elif isinstance(raw_value, float):
                        if col_key in ["latitude", "longitude"]: display_value = f"{raw_value:.5f}"
                        elif col_key in ["baro_altitude_m", "geo_altitude_m"]: display_value = f"{raw_value:.0f}"
                        elif col_key in ["velocity_mps", "true_track_deg", "vertical_rate_mps"]: display_value = f"{raw_value:.1f}"
                        else: display_value = str(raw_value)
                    elif isinstance(raw_value, bool): display_value = str(raw_value)
                    else: display_value = str(raw_value)
                values.append(display_value)
            self.track_table.insert("", 0, values=values)

    def _update_track_map(self, track_data_list: Optional[List[Dict[str, Any]]], current_live_data: Optional[Dict[str, Any]]):
        if not self.detail_map_manager or not self.detail_map_manager.canvas.winfo_exists():
            logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): _update_track_map called but DetailMapManager not ready or canvas gone.")
            self._initial_track_data = track_data_list
            self._initial_live_data = current_live_data
            return

        logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Updating detail map with track and live data.")
        if self.detail_map_manager:
            self.detail_map_manager.clear_map_display()

        valid_track_points_for_bbox: List[Tuple[float, float]] = []
        canonical_track_states_for_drawing: List[CanonicalFlightState] = []
        current_icao_normalized = self.icao24

        if track_data_list:
            for point_dict in track_data_list:
                lat, lon = point_dict.get("latitude"), point_dict.get("longitude")
                if lat is not None and lon is not None:
                    valid_track_points_for_bbox.append((lat, lon))
                try:
                    state = CanonicalFlightState(
                        icao24=current_icao_normalized,
                        timestamp=float(point_dict.get("timestamp", 0)),
                        last_contact_timestamp=float(point_dict.get("timestamp", 0)),
                        latitude=lat, longitude=lon, on_ground=bool(point_dict.get("on_ground", False)),
                        baro_altitude_m=point_dict.get("baro_altitude_m"), 
                        geo_altitude_m=point_dict.get("geo_altitude_m"),
                        velocity_mps=point_dict.get("velocity_mps"), 
                        true_track_deg=point_dict.get("true_track_deg"),
                        vertical_rate_mps=point_dict.get("vertical_rate_mps")
                    )
                    canonical_track_states_for_drawing.append(state)
                except Exception as e:
                    logger.warning(f"Could not convert track point to CanonicalFlightState for drawing: {point_dict}, Error: {e}")
                    continue
        
        current_flight_for_map_drawing: List[CanonicalFlightState] = []
        if current_live_data:
            live_lat, live_lon = current_live_data.get("latitude"), current_live_data.get("longitude")
            if live_lat is not None and live_lon is not None:
                 valid_track_points_for_bbox.append((live_lat, live_lon))
            try:
                live_icao = current_live_data.get("icao24", current_icao_normalized)
                if isinstance(live_icao, str): live_icao = live_icao.lower().strip()
                else: live_icao = current_icao_normalized

                live_state = CanonicalFlightState(
                    icao24=live_icao, 
                    callsign=current_live_data.get("callsign"),
                    origin_country=current_live_data.get("origin_country"), 
                    timestamp=float(current_live_data.get("timestamp", time.time())),
                    last_contact_timestamp=float(current_live_data.get("last_contact_timestamp", time.time())),
                    latitude=live_lat, longitude=live_lon, 
                    baro_altitude_m=current_live_data.get("baro_altitude_m"),
                    geo_altitude_m=current_live_data.get("geo_altitude_m"), 
                    on_ground=bool(current_live_data.get("on_ground", False)), 
                    velocity_mps=current_live_data.get("velocity_mps"), 
                    true_track_deg=current_live_data.get("true_track_deg"),
                    vertical_rate_mps=current_live_data.get("vertical_rate_mps"), 
                    squawk=current_live_data.get("squawk"),
                    spi=bool(current_live_data.get("spi")), 
                    position_source=current_live_data.get("position_source")
                )
                current_flight_for_map_drawing = [live_state]
            except Exception as e:
                logger.warning(f"Could not convert live data to CanonicalFlightState for drawing: {current_live_data}, Error: {e}")

        if not valid_track_points_for_bbox:
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): No valid track points or live position to display on map.")
            if self.detail_map_manager: self.detail_map_manager._display_placeholder_text("No flight track data available to display.")
            return
        
        if not self.detail_map_manager:
            logger.error(f"FullDetailsWindow ({self.icao24.upper()}): self.detail_map_manager is None before populating its data. Aborting map update.")
            return

        with self.detail_map_manager._map_data_lock:
            self.detail_map_manager.flight_tracks_gui.clear()
            track_deque = deque(maxlen=(len(canonical_track_states_for_drawing) + 5) if canonical_track_states_for_drawing else 5)
            for state in canonical_track_states_for_drawing:
                if state.latitude is not None and state.longitude is not None and state.timestamp is not None:
                    track_deque.append((state.latitude, state.longitude, state.timestamp))
            if track_deque:
                self.detail_map_manager.flight_tracks_gui[current_icao_normalized] = track_deque
            
            self.detail_map_manager._current_flights_to_display_gui = current_flight_for_map_drawing

        if len(valid_track_points_for_bbox) == 1:
            lat, lon = valid_track_points_for_bbox[0]
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Single point track/live. Centering map with patch.")
            if self.detail_map_manager: self.detail_map_manager.center_map_and_fit_patch(lat, lon, patch_size_km=DEFAULT_SINGLE_POINT_PATCH_KM)
        else:
            min_lat, max_lat = min(p[0] for p in valid_track_points_for_bbox), max(p[0] for p in valid_track_points_for_bbox)
            min_lon, max_lon = min(p[1] for p in valid_track_points_for_bbox), max(p[1] for p in valid_track_points_for_bbox)
            padding_deg = 0.05
            padding_lat_eff = max(padding_deg, (max_lat - min_lat) * 0.15)
            padding_lon_eff = max(padding_deg, (max_lon - min_lon) * 0.15)
            track_bbox = {
                "lat_min": max(-90.0, min_lat - padding_lat_eff), "lon_min": max(-180.0, min_lon - padding_lon_eff),
                "lat_max": min(90.0, max_lat + padding_lat_eff), "lon_max": min(180.0, max_lon + padding_lon_eff),
            }

            if _is_valid_bbox_dict(track_bbox):
                logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Requesting detail map render for calculated BBox of track: {track_bbox}")
                # --- MODIFICA QUI ---
                # Rimuoviamo l'argomento keyword inesistente
                if self.detail_map_manager:
                    self.detail_map_manager._request_map_render_for_bbox(track_bbox)
                # --- FINE MODIFICA ---
            else:
                logger.warning(f"FullDetailsWindow ({self.icao24.upper()}): Calculated track BBox is invalid: {track_bbox}. Attempting fallback.")
                last_known_lat, last_known_lon = valid_track_points_for_bbox[-1]
                if self.detail_map_manager:
                    self.detail_map_manager.center_map_and_fit_patch(last_known_lat, last_known_lon, patch_size_km=DEFAULT_SINGLE_POINT_PATCH_KM * 2)

    def _open_jetphotos_link_action(self, event=None):
        if self.current_jetphotos_url:
            try:
                webbrowser.open_new_tab(self.current_jetphotos_url)
                logger.info(f"Opening JetPhotos link: {self.current_jetphotos_url}")
            except Exception as e:
                logger.error(f"Failed to open JetPhotos link {self.current_jetphotos_url}: {e}")
        else:
            logger.warning("No JetPhotos URL to open for current aircraft.")

    def center_window(self):
        self.update_idletasks()
        width = self.winfo_width()
        height = self.winfo_height()
        if width <= 1: width = self.winfo_reqwidth() if self.winfo_reqwidth() > 1 else 1100
        if height <= 1: height = self.winfo_reqheight() if self.winfo_reqheight() > 1 else 700

        x_screen = self.winfo_screenwidth()
        y_screen = self.winfo_screenheight()
        x = (x_screen // 2) - (width // 2)
        y = (y_screen // 2) - (height // 2)

        if x + width > x_screen: x = x_screen - width
        if y + height > y_screen: y = y_screen - height
        if x < 0: x = 0
        if y < 0: y = 0

        if width > 0 and height > 0 : self.geometry(f"{width}x{height}+{x}+{y}")

    def _on_closing_details_window(self):
        logger.info(f"FullFlightDetailsWindow for {self.icao24.upper()} is closing.")
        if self.detail_map_manager:
            logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Requesting shutdown for detail_map_manager worker.")
            try:
                self.detail_map_manager.shutdown_worker()
            except Exception as e:
                logger.error(f"FullDetailsWindow ({self.icao24.upper()}): Error during detail_map_manager worker shutdown: {e}", exc_info=True)
        
        if self.controller and hasattr(self.controller, "details_window_closed"):
            try:
                self.controller.details_window_closed(self.icao24)
                logger.info(f"FullDetailsWindow ({self.icao24.upper()}): Notified controller of closure.")
            except Exception as e_notify_close:
                 logger.error(f"FullDetailsWindow ({self.icao24.upper()}): Error notifying controller of details window closure: {e_notify_close}", exc_info=True)

        self.destroy()

if __name__ == "__main__":
    root_test = tk.Tk()
    root_test.title("Main Window (Test)")
    sample_static = {
        "icao24": "TST001", "registration": "N-TEST", "manufacturername": "TestAircraft Co.", "model": "SkyTester Pro",
        "typecode": "TSPR", "operator": "Test Flight Ops", "built_year": 2022, "categorydescription": "Experimental Test Vehicle",
        "country": "Testland", "timestamp_metadata": time.time() - 3600 * 24 * 30,
        "firstflightdate": "2022-01-15"
    }
    sample_live = {
        "icao24": "tst001", 
        "callsign": "TEST01", "baro_altitude_m": 10000.0, "geo_altitude_m": 10050.0, "velocity_mps": 250.5,
        "vertical_rate_mps": 5.2, "true_track_deg": 123.4, "on_ground": False, "squawk": "7000",
        "origin_country": "Testland Live", "timestamp": time.time() - 60, "last_contact_timestamp": time.time() - 58,
        "latitude": 45.15, "longitude": 9.15
    }
    sample_track = [
        {"latitude": 45.0, "longitude": 9.0, "baro_altitude_m": 9000, "timestamp": time.time() - 300, "on_ground": False},
        {"latitude": 45.1, "longitude": 9.1, "baro_altitude_m": 9500, "timestamp": time.time() - 180, "on_ground": False},
        {"latitude": 45.2, "longitude": 9.2, "baro_altitude_m": 10000, "timestamp": time.time() - 60, "on_ground": False},
    ]
    sample_track_single_point = [
        {"latitude": 46.0, "longitude": 10.0, "baro_altitude_m": 8000, "timestamp": time.time() - 120, "on_ground": False}
    ]
    sample_live_only = {
        "icao24": "tst002", "callsign": "LIVEONLY", "latitude": 45.5, "longitude": 9.5, "baro_altitude_m": 5000,
        "timestamp": time.time()-10, "last_contact_timestamp": time.time()-10, "on_ground": False
    }

    def open_details_test(static, live, track, icao="TST001"):
        if hasattr(root_test, "details_win_instance_test") and root_test.details_win_instance_test.winfo_exists():
            root_test.details_win_instance_test.destroy()

        details_window = FullFlightDetailsWindow(root_test, icao) 
        details_window._initial_static_data = static
        details_window._initial_live_data = live
        details_window._initial_track_data = track
        details_window.update_details(static, live, track)
        root_test.details_win_instance_test = details_window

    ttk.Button(root_test, text="Open Full Details (Multi-Point Track)", command=lambda: open_details_test(sample_static, sample_live, sample_track, icao="tst001")).pack(padx=20, pady=5)
    ttk.Button(root_test, text="Open Full Details (Single-Point Track)", command=lambda: open_details_test(sample_static, sample_live, sample_track_single_point, icao="tst001")).pack(padx=20, pady=5)
    ttk.Button(root_test, text="Open Full Details (Live Only, No Track)", command=lambda: open_details_test(None, sample_live_only, None, icao="tst002")).pack(padx=20, pady=5)
    ttk.Button(root_test, text="Open Full Details (No Track, No Live)", command=lambda: open_details_test(sample_static, None, None, icao="tst001")).pack(padx=20, pady=5)

    root_test.mainloop()