# FlightMonitor/gui/main_window.py
"""
Main window of the Flight Monitor application.
Handles the layout with multiple notebooks for functions and views,
user interactions, status display including a semaphore, and logging.
"""
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
from tkinter import Menu
from tkinter import font as tkFont
from typing import List, Dict, Optional, Tuple, Any
import logging
import os
from datetime import datetime, timezone
import webbrowser

from ..data import config as app_config

from ..utils.logger import (
    get_logger,
    add_tkinter_handler,
    shutdown_logging_system,
)
from ..data.logging_config import LOGGING_CONFIG
from ..data.common_models import CanonicalFlightState
from ..utils.gui_utils import (
    GUI_STATUS_OK,
    GUI_STATUS_WARNING,
    GUI_STATUS_ERROR,
    GUI_STATUS_FETCHING,
    GUI_STATUS_UNKNOWN,
    GUI_STATUS_PERMANENT_FAILURE,
)

from .panels.log_status_panel import LogStatusPanel
from .panels.map_tools_panel import MapToolsPanel
from .panels.map_info_panel import MapInfoPanel
from .panels.selected_flight_details_panel import SelectedFlightDetailsPanel
from .panels.function_notebook_panel import FunctionNotebookPanel
from .panels.views_notebook_panel import ViewsNotebookPanel

try:
    from ..map.map_canvas_manager import MapCanvasManager
    from ..map.map_utils import _is_valid_bbox_dict

    MAP_CANVAS_MANAGER_AVAILABLE = True
except ImportError as e_map_import:
    MapCanvasManager = None
    _is_valid_bbox_dict = lambda x: False
    MAP_CANVAS_MANAGER_AVAILABLE = False
    print(
        f"CRITICAL ERROR in MainWindow import: Failed to import MapCanvasManager or map_utils: {e_map_import}. Map functionality will be disabled.",
        flush=True,
    )

try:
    from .dialogs.import_progress_dialog import ImportProgressDialog

    IMPORT_DIALOG_AVAILABLE = True
except ImportError as e_dialog_import:
    ImportProgressDialog = None
    IMPORT_DIALOG_AVAILABLE = False
    print(
        f"ERROR in MainWindow import: Failed to import ImportProgressDialog: {e_dialog_import}. Import progress UI will be basic.",
        flush=True,
    )

module_logger = get_logger(__name__)

BBOX_COLOR_INSIDE = "green4"
BBOX_COLOR_OUTSIDE = "red2"
BBOX_COLOR_PARTIAL = "darkorange"
BBOX_COLOR_NA = "gray50"


class MainWindow:
    def __init__(self, root: tk.Tk, controller: Any):
        self.root = root
        self.controller = controller
        self.root.title("Flight Monitor")
        self.progress_dialog: Optional[ImportProgressDialog] = None
        self.full_flight_details_window: Optional[tk.Toplevel] = None

        if app_config.LAYOUT_START_MAXIMIZED:
            try:
                self.root.state("zoomed")
            except tk.TclError:
                try:
                    self.root.geometry(
                        f"{self.root.winfo_screenwidth()}x{self.root.winfo_screenheight()}+0+0"
                    )
                except tk.TclError:
                    pass

        min_win_w = getattr(app_config, "LAYOUT_WINDOW_MIN_WIDTH", 900)
        min_win_h = getattr(app_config, "LAYOUT_WINDOW_MIN_HEIGHT", 650)
        self.root.minsize(min_win_h, min_win_h) # Corrected min_win_h used twice, should be min_win_w and min_win_h

        self.menubar = Menu(self.root)
        self.file_menu = Menu(self.menubar, tearoff=0)
        self.file_menu.add_command(
            label="Import Aircraft Database (CSV)...",
            command=self._import_aircraft_db_csv,
        )
        self.file_menu.add_separator()
        self.file_menu.add_command(label="Exit", command=self._on_closing)
        self.menubar.add_cascade(label="File", menu=self.file_menu)
        self.root.config(menu=self.menubar)

        self.main_horizontal_paned_window = ttk.PanedWindow(
            self.root, orient=tk.HORIZONTAL
        )
        self.main_horizontal_paned_window.pack(
            fill=tk.BOTH, expand=True, padx=5, pady=5
        )

        self.left_column_frame = ttk.Frame(self.main_horizontal_paned_window)
        self.main_horizontal_paned_window.add(
            self.left_column_frame,
            weight=app_config.LAYOUT_MAIN_HORIZONTAL_WEIGHTS.get("left_column", 25),
        )

        self.left_vertical_paned_window = ttk.PanedWindow(
            self.left_column_frame, orient=tk.VERTICAL
        )
        self.left_vertical_paned_window.pack(fill=tk.BOTH, expand=True)

        self.function_notebook_frame = ttk.Frame(self.left_vertical_paned_window)
        self.left_vertical_paned_window.add(
            self.function_notebook_frame,
            weight=app_config.LAYOUT_LEFT_VERTICAL_WEIGHTS.get("function_notebook", 65),
        )
        self.function_notebook_panel = FunctionNotebookPanel(
            self.function_notebook_frame, self.controller
        )

        self.log_status_area_frame_container = ttk.Frame(self.left_vertical_paned_window)
        self.left_vertical_paned_window.add(
            self.log_status_area_frame_container,
            weight=app_config.LAYOUT_LEFT_VERTICAL_WEIGHTS.get("log_status_area", 35),
        )
        self.log_status_panel = LogStatusPanel(self.log_status_area_frame_container, self.root)

        self.right_column_frame = ttk.Frame(self.main_horizontal_paned_window)
        self.main_horizontal_paned_window.add(
            self.right_column_frame,
            weight=app_config.LAYOUT_MAIN_HORIZONTAL_WEIGHTS.get("right_column", 75),
        )

        self.right_vertical_paned_window = ttk.PanedWindow(
            self.right_column_frame, orient=tk.VERTICAL
        )
        self.right_vertical_paned_window.pack(fill=tk.BOTH, expand=True)

        self.views_notebook_outer_frame = ttk.Frame(self.right_vertical_paned_window)
        self.right_vertical_paned_window.add(
            self.views_notebook_outer_frame,
            weight=app_config.LAYOUT_RIGHT_VERTICAL_WEIGHTS.get("views_notebook", 80),
        )
        self.views_notebook_panel = ViewsNotebookPanel(self.views_notebook_outer_frame)
        self.flight_canvas = self.views_notebook_panel.get_map_canvas()
        self.map_manager_instance: Optional[MapCanvasManager] = None

        self.map_tools_info_area_frame = ttk.Frame(
            self.right_vertical_paned_window, padding=(0, 5, 0, 0)
        )
        self.right_vertical_paned_window.add(
            self.map_tools_info_area_frame,
            weight=app_config.LAYOUT_RIGHT_VERTICAL_WEIGHTS.get("map_tools_info", 20),
        )

        self.bottom_panel_container = ttk.Frame(self.map_tools_info_area_frame)
        self.bottom_panel_container.pack(fill=tk.BOTH, expand=True)

        bottom_panel_weights = getattr(
            app_config,
            "LAYOUT_BOTTOM_PANELS_HORIZONTAL_WEIGHTS",
            {"map_tools": 1, "map_info": 2, "flight_details": 2},
        )
        self.bottom_panel_container.columnconfigure(
            0, weight=bottom_panel_weights.get("map_tools", 1)
        )
        self.bottom_panel_container.columnconfigure(
            1, weight=bottom_panel_weights.get("map_info", 2)
        )
        self.bottom_panel_container.columnconfigure(
            2, weight=bottom_panel_weights.get("flight_details", 2)
        )

        self.map_tool_frame = ttk.LabelFrame(
            self.bottom_panel_container, text="Map Tools", padding=5
        )
        self.map_tool_frame.grid(row=0, column=0, sticky="nsew", padx=(0, 2))
        self.map_tools_panel = MapToolsPanel(self.map_tool_frame, self.controller)

        self.map_info_panel_frame = ttk.LabelFrame(
            self.bottom_panel_container, text="Map Information", padding=10
        )
        self.map_info_panel_frame.grid(row=0, column=1, sticky="nsew", padx=2)
        self.map_info_panel = MapInfoPanel(self.map_info_panel_frame)

        self.selected_flight_details_frame = ttk.LabelFrame(
            self.bottom_panel_container, text="Selected Flight Details", padding=10
        )
        self.selected_flight_details_frame.grid(
            row=0, column=2, sticky="nsew", padx=(2, 0)
        )
        self.selected_flight_details_panel = SelectedFlightDetailsPanel(
            self.selected_flight_details_frame, self.controller
        )

        if self.log_status_panel.get_log_widget() and self.root:
            add_tkinter_handler(
                gui_log_widget=self.log_status_panel.get_log_widget(),
                root_tk_instance_for_gui_handler=self.root,
                logging_config_dict=LOGGING_CONFIG,
            )
        else:
            module_logger.error(
                "LogStatusPanel or root not available in MainWindow init for logger setup."
            )

        self.root.protocol("WM_DELETE_WINDOW", self._on_closing)
        self.root.after(100, self._delayed_initialization)
        module_logger.info(
            "MainWindow basic structure initialized. Delayed init pending."
        )

    def _on_closing(self):
        module_logger.info("Main window closing event triggered.")
        user_confirmed_quit = (
            messagebox.askokcancel(
                "Quit", "Do you want to quit Flight Monitor?", parent=self.root
            )
            if self.root.winfo_exists()
            else True
        )
        if user_confirmed_quit:
            if self.controller and hasattr(self.controller, "on_application_exit"):
                try:
                    self.controller.on_application_exit()
                except Exception as e:
                    module_logger.error(
                        f"Error during controller.on_application_exit: {e}",
                        exc_info=True,
                    )
            try:
                shutdown_logging_system()
            except Exception as e:
                module_logger.error(
                    f"Error during shutdown_logging_system: {e}", exc_info=True
                )

            if hasattr(self, "root") and self.root.winfo_exists():
                try:
                    self.root.destroy()
                except Exception:
                    pass
        else:
            module_logger.info("User cancelled quit.")

    def _import_aircraft_db_csv(self):
        if not self.controller:
            self.show_error_message(
                "Controller Error", "Application controller not available."
            )
            module_logger.error("Controller not available for aircraft DB import.")
            return

        if not hasattr(
            self.controller, "import_aircraft_database_from_file_with_progress"
        ):
            self.show_error_message(
                "Function Error",
                "Progress import function not available in controller.",
            )
            module_logger.error(
                "Method 'import_aircraft_database_from_file_with_progress' missing in controller."
            )
            return

        filepath = filedialog.askopenfilename(
            master=self.root,
            title="Select Aircraft Database CSV File",
            filetypes=(("CSV files", "*.csv"), ("All files", "*.*")),
        )
        if filepath:
            module_logger.info(f"GUI: Selected CSV file for import: {filepath}")

            if IMPORT_DIALOG_AVAILABLE and ImportProgressDialog is not None:
                if self.progress_dialog and self.progress_dialog.winfo_exists():
                    try:
                        self.progress_dialog.destroy()
                    except tk.TclError:
                        module_logger.warning(
                            "Could not destroy previous progress dialog cleanly."
                        )
                self.progress_dialog = ImportProgressDialog(
                    self.root, file_name=filepath
                )
                self.controller.import_aircraft_database_from_file_with_progress(
                    filepath, self.progress_dialog
                )
            else:
                module_logger.warning(
                    "ImportProgressDialog class not available. Using basic status update for import."
                )
                if hasattr(
                    self.controller, "import_aircraft_database_from_file"
                ):
                    self.show_info_message(
                        "Import Started",
                        f"Starting import of {os.path.basename(filepath)}...\nThis might take a while. Check logs for completion.",
                    )
                    self.controller.import_aircraft_database_from_file(filepath)
                else:
                    self.show_error_message(
                        "Import Error",
                        "Import progress UI is not available and no fallback import method found.",
                    )
        else:
            module_logger.info("GUI: CSV import cancelled by user.")

    def _delayed_initialization(self):
        if not self.root.winfo_exists():
            module_logger.warning(
                "Root window destroyed before delayed initialization."
            )
            return

        if MAP_CANVAS_MANAGER_AVAILABLE and MapCanvasManager is not None:
            default_map_bbox = {
                "lat_min": app_config.DEFAULT_BBOX_LAT_MIN,
                "lon_min": app_config.DEFAULT_BBOX_LON_MIN,
                "lat_max": app_config.DEFAULT_BBOX_LAT_MAX,
                "lon_max": app_config.DEFAULT_BBOX_LON_MAX,
            }
            initial_track_len = self.function_notebook_panel.get_track_length_input()

            self.root.after(
                200, self._initialize_map_manager, default_map_bbox, initial_track_len
            )
        else:
            module_logger.error("MapCanvasManager class not available post-init.")
            fallback_canvas_w = self.views_notebook_panel.canvas_width
            fallback_canvas_h = self.views_notebook_panel.canvas_height
            self.root.after(
                50,
                lambda w=fallback_canvas_w, h=fallback_canvas_h: self._update_map_placeholder(
                    "Map functionality disabled (Import Error)."
                ),
            )

        self.root.after(10, self.function_notebook_panel._on_mode_change)
        module_logger.info(
            "MainWindow fully initialized. Delegating initial mode setup."
        )

    def _initialize_map_manager(
        self, initial_bbox_for_map: Dict[str, float], initial_track_length: int
    ):
        if not MAP_CANVAS_MANAGER_AVAILABLE or MapCanvasManager is None:
            self._update_map_placeholder("Map Error: Manager class missing.")
            if self.controller and hasattr(self.controller, "update_general_map_info"):
                self.controller.update_general_map_info()
            return

        current_flight_canvas = self.views_notebook_panel.get_map_canvas()
        if not current_flight_canvas or not current_flight_canvas.winfo_exists():
            module_logger.warning(
                "Flight canvas does not exist. Cannot initialize MapCanvasManager."
            )
            return

        canvas_w, canvas_h = (
            current_flight_canvas.winfo_width(),
            current_flight_canvas.winfo_height(),
        )
        if canvas_w <= 1:
            canvas_w = self.views_notebook_panel.canvas_width
        if canvas_h <= 1:
            canvas_h = self.views_notebook_panel.canvas_height

        if canvas_w > 1 and canvas_h > 1:
            try:
                self.map_manager_instance = MapCanvasManager(
                    app_controller=self.controller,
                    tk_canvas=current_flight_canvas,
                    initial_bbox_dict=initial_bbox_for_map,
                )
                if self.controller and hasattr(self.controller, "set_map_track_length"):
                    try:
                        self.controller.set_map_track_length(initial_track_length)
                        module_logger.info(
                            f"Initial map track length set to {initial_track_length} via controller."
                        )
                    except Exception as e_trk:
                        module_logger.error(
                            f"Error setting initial track length for map manager: {e_trk}"
                        )
                else:
                    module_logger.warning(
                        "Controller or set_map_track_length not available for initial setup."
                    )

                if self.controller and hasattr(
                    self.controller, "update_general_map_info"
                ):
                    self.controller.update_general_map_info()

            except Exception as e_init:
                module_logger.critical(
                    f"Failed to initialize MapCanvasManager: {e_init}", exc_info=True
                )
                self.show_error_message(
                    "Map Error", f"Could not initialize map: {e_init}"
                )
                self._update_map_placeholder(f"Map Error: Init failed.\n{e_init}")
                if self.controller and hasattr(
                    self.controller, "update_general_map_info"
                ):
                    self.controller.update_general_map_info()
        else:
            if self.root.winfo_exists():
                module_logger.info(
                    "Canvas not sized yet, retrying map manager initialization."
                )
                self.root.after(
                    300,
                    self._initialize_map_manager,
                    initial_bbox_for_map,
                    initial_track_length,
                )

    def _recreate_map_tools_content(self, parent_frame: ttk.Frame):
        pass

    def _recreate_map_info_content(self, parent_frame: ttk.Frame):
        pass

    def _create_selected_flight_details_content(self, parent_frame: ttk.LabelFrame):
        pass

    def update_semaphore_and_status(self, status_level: str, message: str):
        if hasattr(self, "log_status_panel") and self.log_status_panel:
            self.log_status_panel.update_status_display(status_level, message)
        else:
            print(f"Status update (LogStatusPanel not ready): {status_level}: {message}", flush=True)

        log_level_to_use = logging.INFO
        if status_level == GUI_STATUS_ERROR:
            log_level_to_use = logging.ERROR
        elif status_level == GUI_STATUS_PERMANENT_FAILURE:
            log_level_to_use = logging.CRITICAL
        elif status_level == GUI_STATUS_WARNING:
            log_level_to_use = logging.WARNING
        elif status_level in [GUI_STATUS_FETCHING, GUI_STATUS_OK, GUI_STATUS_UNKNOWN]:
            log_level_to_use = logging.DEBUG
        module_logger.log(
            log_level_to_use,
            f"GUI Status Update: Level='{status_level}', Message='{message}'",
        )

    def _reset_gui_to_stopped_state(
        self, status_message: Optional[str] = "Monitoring stopped."
    ):
        if hasattr(self, "function_notebook_panel") and self.function_notebook_panel:
            self.function_notebook_panel.set_monitoring_button_states(False)
        else:
            if hasattr(self, "start_button") and self.start_button.winfo_exists():
                self.start_button.config(state=tk.NORMAL)
            if hasattr(self, "stop_button") and self.stop_button.winfo_exists():
                self.stop_button.config(state=tk.DISABLED)
            if hasattr(self, "live_radio") and self.live_radio.winfo_exists():
                self.live_radio.config(state=tk.NORMAL)
            if hasattr(self, "history_radio") and self.history_radio.winfo_exists():
                self.history_radio.config(state=tk.NORMAL)

        if hasattr(self, "function_notebook_panel") and self.function_notebook_panel:
            self.function_notebook_panel._update_internal_controls_state()

        status_level = GUI_STATUS_OK
        if status_message and (
            "failed" in status_message.lower() or "error" in status_message.lower()
        ):
            status_level = GUI_STATUS_ERROR
        elif status_message and "warning" in status_message.lower():
            status_level = GUI_STATUS_WARNING

        if hasattr(self, "root") and self.root.winfo_exists():
            self.update_semaphore_and_status(
                status_level, status_message if status_message else "System Ready."
            )

    def _should_show_main_placeholder(self) -> bool:
        current_flight_canvas = self.views_notebook_panel.get_map_canvas() if hasattr(self, "views_notebook_panel") else None
        return not (
            current_flight_canvas
            and hasattr(self, "map_manager_instance")
            and self.map_manager_instance is not None
            and MAP_CANVAS_MANAGER_AVAILABLE
        )

    def _update_map_placeholder(self, text_to_display: str):
        current_flight_canvas = self.views_notebook_panel.get_map_canvas() if hasattr(self, "views_notebook_panel") else None

        if not (
            current_flight_canvas
            and current_flight_canvas.winfo_exists()
        ):
            return

        if (
            not self._should_show_main_placeholder()
        ):
            try:
                current_flight_canvas.delete("placeholder_text")
            except:
                pass
            return

        try:
            current_flight_canvas.delete("placeholder_text")
            canvas_w, canvas_h = (
                current_flight_canvas.winfo_width(),
                current_flight_canvas.winfo_height(),
            )
            if canvas_w <= 1: canvas_w = self.views_notebook_panel.canvas_width
            if canvas_h <= 1: canvas_h = self.views_notebook_panel.canvas_height

            if canvas_w > 1 and canvas_h > 1:
                current_flight_canvas.create_text(
                    canvas_w / 2,
                    canvas_h / 2,
                    text=text_to_display,
                    tags="placeholder_text",
                    fill="gray50",
                    font=("Arial", 12, "italic"),
                    justify=tk.CENTER,
                    width=canvas_w - 40,
                )
        except tk.TclError:
            pass
        except Exception as e_placeholder_draw:
            module_logger.error(f"Error drawing placeholder: {e_placeholder_draw}")

    def _on_mode_change(self):
        pass

    def _on_function_tab_change(self, event: Optional[tk.Event] = None):
        pass

    def _update_controls_state_based_on_mode_and_tab(self):
        pass

    def _set_bbox_entries_state(self, state: str):
        pass

    def _start_monitoring(self):
        pass

    def _stop_monitoring(self):
        pass

    def get_bounding_box_from_gui(self) -> Optional[Dict[str, float]]:
        if hasattr(self, "function_notebook_panel") and self.function_notebook_panel:
            return self.function_notebook_panel.get_bounding_box_input()
        else:
            module_logger.error("FunctionNotebookPanel not initialized for get_bounding_box_from_gui.")
            return None

    def update_bbox_gui_fields(self, bbox_dict: Dict[str, float]):
        if hasattr(self, "function_notebook_panel") and self.function_notebook_panel:
            self.function_notebook_panel.update_bbox_gui_fields(bbox_dict)
        else:
            module_logger.warning("FunctionNotebookPanel not initialized for update_bbox_gui_fields.")

    def display_flights_on_canvas(
        self,
        flight_states: List[CanonicalFlightState],
        _active_bbox_context: Optional[
            Dict[str, float]
        ],
    ):
        current_flight_canvas = self.views_notebook_panel.get_map_canvas() if hasattr(self, "views_notebook_panel") else None

        if not (
            current_flight_canvas
            and hasattr(self, "map_manager_instance")
            and self.map_manager_instance is not None
            and MAP_CANVAS_MANAGER_AVAILABLE
        ):
            if hasattr(self, "root") and self.root.winfo_exists():
                self._update_map_placeholder("Map N/A to display flights.")
            return

        try:
            self.map_manager_instance.update_flights_on_map(flight_states)
            if (
                not flight_states and not self._should_show_main_placeholder()
            ):
                pass
            elif (
                not flight_states and self._should_show_main_placeholder()
            ):
                self._update_map_placeholder("No flights in the selected area.")

        except Exception as e:
            module_logger.error(
                f"Error in display_flights_on_canvas: {e}", exc_info=True
            )
            self.show_error_message(
                "Map Display Error", "Could not update flights on map."
            )

    def clear_all_views_data(self):
        module_logger.info("GUI: Clearing all views data.")
        if (
            hasattr(self, "map_manager_instance")
            and self.map_manager_instance
            and MAP_CANVAS_MANAGER_AVAILABLE
        ):
            try:
                self.map_manager_instance.clear_map_display()
            except Exception as e:
                module_logger.warning(f"Error clearing map via map manager: {e}")
        elif (
            self._should_show_main_placeholder()
        ):
            mode = self.function_notebook_panel.get_selected_mode() if hasattr(self, "function_notebook_panel") else "Unknown"
            active_func_tab_text = self.function_notebook_panel.get_active_function_tab_text() if hasattr(self, "function_notebook_panel") else ""
            
            text = f"Map - {mode}. Data cleared."
            if mode == "Live" and "Live: Area Monitor" in active_func_tab_text:
                text = "Map - Live. Define area and Start."
            elif mode == "History" and "History" in active_func_tab_text:
                text = "Map - History. (Coming Soon)"
            elif mode == "Live" and "Live: Airport" in active_func_tab_text:
                text = "Map - Live Airport. (Coming Soon)"
            self._update_map_placeholder(text)

        if hasattr(self, "selected_flight_details_panel"):
            self.selected_flight_details_panel.update_details(None)
        else:
            module_logger.warning("SelectedFlightDetailsPanel not initialized for clearing.")


    # MODIFIED: Corrected parameter passing
    # WHY: The 'flight_data' parameter received by this method was not being passed
    #      to the delegated call on `selected_flight_details_panel.update_details`.
    # HOW: Changed `self.selected_flight_details_panel.update_details(None)` to
    #      `self.selected_flight_details_panel.update_details(flight_data)`.
    def update_selected_flight_details(self, flight_data: Optional[Dict[str, Any]]):
        """
        Delegates the update of selected flight details to the SelectedFlightDetailsPanel.

        Args:
            flight_data: A dictionary containing flight information.
        """
        if hasattr(self, "selected_flight_details_panel") and self.selected_flight_details_panel:
            self.selected_flight_details_panel.update_details(flight_data) # FIX APPLIED HERE
        else:
            module_logger.warning("SelectedFlightDetailsPanel not initialized for updating.")


    def show_error_message(self, title: str, message: str):
        status_msg = f"Error: {message[:70]}{'...' if len(message)>70 else ''}"
        if hasattr(self, "root") and self.root.winfo_exists():
            self.update_semaphore_and_status(GUI_STATUS_ERROR, status_msg)
            try:
                messagebox.showerror(title, message, parent=self.root)
            except tk.TclError:
                pass
        else:
            print(f"ERROR (No GUI messagebox): {title} - {message}", flush=True)

    def show_info_message(self, title: str, message: str):
        if hasattr(self, "root") and self.root.winfo_exists():
            try:
                messagebox.showinfo(title, message, parent=self.root)
            except tk.TclError:
                pass
        else:
            print(f"INFO (No GUI messagebox): {title} - {message}", flush=True)

    def show_map_context_menu(
        self, latitude: float, longitude: float, screen_x: int, screen_y: int
    ):
        if (
            hasattr(self, "map_manager_instance")
            and self.map_manager_instance
            and hasattr(self.map_manager_instance, "show_map_context_menu_from_gui")
            and MAP_CANVAS_MANAGER_AVAILABLE
        ):
            try:
                self.map_manager_instance.show_map_context_menu_from_gui(
                    latitude, longitude, screen_x, screen_y
                )
            except Exception as e:
                module_logger.error(
                    f"Error delegating context menu to MapCanvasManager: {e}",
                    exc_info=True,
                )
        else:
            module_logger.warning(
                "Map manager or context menu method not available for GUI."
            )

    def update_clicked_map_info(
        self,
        lat_deg: Optional[float],
        lon_deg: Optional[float],
        lat_dms: str,
        lon_dms: str,
    ):
        if hasattr(self, "map_info_panel") and self.map_info_panel:
            self.map_info_panel.update_clicked_map_info(lat_deg, lon_deg, lat_dms, lon_dms)
        else:
            module_logger.warning("MapInfoPanel not initialized for update_clicked_map_info.")

    def update_general_map_info_display(
        self,
        zoom: Optional[int],
        map_size_str: str,
        map_geo_bounds: Optional[Tuple[float, float, float, float]],
        target_bbox_input: Optional[Dict[str, float]],
        flight_count: Optional[int],
    ):
        if hasattr(self, "map_info_panel") and self.map_info_panel:
            self.map_info_panel.update_general_map_info_display(
                zoom, map_size_str, map_geo_bounds, target_bbox_input, flight_count
            )
        else:
            module_logger.warning("MapInfoPanel not initialized for update_general_map_info_display.")

    def _on_track_length_change(self):
        pass