# FlightMonitor/gui/panels/map_tools_panel.py
"""
Panel for controlling map interactions (zoom, pan, center & fit).
"""
import tkinter as tk
from tkinter import ttk
from typing import Any, Optional, Tuple

from flightmonitor.utils.logger import get_logger
from flightmonitor.data import config as app_config # Used for default patch size for center & fit

module_logger = get_logger(__name__)

# Constants for map tools, if any specific to this panel
DEFAULT_CENTER_PATCH_SIZE_KM = 100 # Default value for the "Patch (km)" entry


class MapToolsPanel:
    """
    Manages the GUI elements for map control, including zoom, pan, and centering.
    """

    def __init__(self, parent_frame: ttk.Frame, controller: Any):
        """
        Initializes the MapToolsPanel.

        Args:
            parent_frame: The parent ttk.Frame where this panel will be placed.
            controller: The application controller instance to delegate map actions.
        """
        self.parent_frame = parent_frame
        self.controller = controller

        # --- Zoom Controls ---
        # Crea un frame per i controlli di zoom e i relativi bottoni.
        self.zoom_frame = ttk.Frame(self.parent_frame)
        self.zoom_frame.pack(side=tk.TOP, pady=(0, 10))

        ttk.Button(self.zoom_frame, text="Zoom In (+)", command=self._on_zoom_in).pack(
            side=tk.LEFT, padx=2
        )
        ttk.Button(self.zoom_frame, text="Zoom Out (-)", command=self._on_zoom_out).pack(
            side=tk.LEFT, padx=2
        )

        # --- Pan Controls ---
        # Crea un frame per i controlli di pan (spostamento) e i relativi bottoni, disposti a croce.
        self.pan_frame = ttk.Frame(self.parent_frame)
        self.pan_frame.pack(side=tk.TOP, pady=(0, 10))

        ttk.Button(self.pan_frame, text="Up", command=lambda: self._on_pan("up")).grid(
            row=0, column=1, padx=2, pady=2
        )
        ttk.Button(self.pan_frame, text="Left", command=lambda: self._on_pan("left")).grid(
            row=1, column=0, padx=2, pady=2
        )
        ttk.Button(
            self.pan_frame, text="Right", command=lambda: self._on_pan("right")
        ).grid(row=1, column=2, padx=2, pady=2)
        ttk.Button(self.pan_frame, text="Down", command=lambda: self._on_pan("down")).grid(
            row=2, column=1, padx=2, pady=2
        )
        # Configura le colonne per garantire un allineamento corretto dei bottoni di pan.
        self.pan_frame.columnconfigure(0, weight=1)
        self.pan_frame.columnconfigure(2, weight=1)

        # --- Center Map Controls ---
        # Crea un LabelFrame per i controlli di centramento mappa, inclusi input per lat, lon e dimensione patch.
        self.center_frame = ttk.LabelFrame(
            self.parent_frame, text="Center Map", padding=5
        )
        self.center_frame.pack(side=tk.TOP, fill=tk.X, pady=(5, 0))
        # Configura le colonne per gli input di lat/lon/patch.
        self.center_frame.columnconfigure(1, weight=1)
        self.center_frame.columnconfigure(3, weight=1)

        ttk.Label(self.center_frame, text="Lat:").grid(
            row=0, column=0, padx=(0, 2), pady=2, sticky=tk.W
        )
        self.center_lat_var = tk.StringVar()
        self.center_lat_entry = ttk.Entry(
            self.center_frame, textvariable=self.center_lat_var, width=10
        )
        self.center_lat_entry.grid(row=0, column=1, padx=(0, 5), pady=2, sticky=tk.EW)

        ttk.Label(self.center_frame, text="Lon:").grid(
            row=0, column=2, padx=(5, 2), pady=2, sticky=tk.W
        )
        self.center_lon_var = tk.StringVar()
        self.center_lon_entry = ttk.Entry(
            self.center_frame, textvariable=self.center_lon_var, width=10
        )
        self.center_lon_entry.grid(row=0, column=3, padx=(0, 0), pady=2, sticky=tk.EW)

        ttk.Label(self.center_frame, text="Patch (km):").grid(
            row=1, column=0, padx=(0, 2), pady=2, sticky=tk.W
        )
        self.center_patch_size_var = tk.StringVar(value=str(DEFAULT_CENTER_PATCH_SIZE_KM))
        self.center_patch_size_entry = ttk.Entry(
            self.center_frame, textvariable=self.center_patch_size_var, width=7
        )
        self.center_patch_size_entry.grid(
            row=1, column=1, padx=(0, 5), pady=2, sticky=tk.W
        )

        self.center_map_button = ttk.Button(
            self.center_frame, text="Center & Fit Patch", command=self._on_center_and_fit
        )
        self.center_map_button.grid(
            row=1, column=2, columnspan=2, padx=5, pady=5, sticky=tk.E
        )

        module_logger.debug("MapToolsPanel initialized.")

    def _on_zoom_in(self):
        """Delegates the 'zoom in' action to the application controller."""
        if self.controller and hasattr(self.controller, "map_zoom_in"):
            self.controller.map_zoom_in()
        else:
            module_logger.warning("Controller or map_zoom_in method not available.")

    def _on_zoom_out(self):
        """Delegates the 'zoom out' action to the application controller."""
        if self.controller and hasattr(self.controller, "map_zoom_out"):
            self.controller.map_zoom_out()
        else:
            module_logger.warning("Controller or map_zoom_out method not available.")

    def _on_pan(self, direction: str):
        """
        Delegates a 'pan' action in a specified direction to the application controller.

        Args:
            direction: The direction to pan ("up", "down", "left", "right").
        """
        if self.controller and hasattr(self.controller, "map_pan_direction"):
            self.controller.map_pan_direction(direction)
        else:
            module_logger.warning(
                f"Controller or map_pan_direction method not available for pan '{direction}'."
            )

    def _on_center_and_fit(self):
        """
        Retrieves latitude, longitude, and patch size from GUI entries and
        delegates the 'center and fit' action to the application controller.
        Includes input validation and error reporting via MainWindow.
        """
        try:
            # Retrieve string values from Tkinter variables
            lat_str = self.center_lat_var.get()
            lon_str = self.center_lon_var.get()
            patch_str = self.center_patch_size_var.get()

            # Input validation: check for empty strings
            if not lat_str or not lon_str or not patch_str:
                self._show_error_message(
                    "Input Error", "Latitude, Longitude, and Patch size are required."
                )
                return

            # Convert string values to floats
            lat = float(lat_str)
            lon = float(lon_str)
            patch = float(patch_str)

            # Validate numerical ranges for geographic coordinates and patch size
            if not (-90 <= lat <= 90 and -180 <= lon <= 180 and patch > 0):
                self._show_error_message(
                    "Input Error",
                    "Invalid latitude (-90 to 90), longitude (-180 to 180), or patch size (>0).",
                )
                return

            # Delegate the action to the controller
            if self.controller and hasattr(self.controller, "map_center_on_coords_and_fit_patch"):
                self.controller.map_center_on_coords_and_fit_patch(lat, lon, patch)
            else:
                module_logger.warning("Controller or map_center_on_coords_and_fit_patch method not available.")
                self._show_error_message(
                    "Error", "Map center function not available (controller issue)."
                )

        except ValueError:
            # Catch errors if float conversion fails (e.g., non-numeric input)
            self._show_error_message(
                "Input Error",
                "Latitude, Longitude, and Patch size must be valid numbers.",
            )
        except Exception as e:
            # Catch any other unexpected errors
            module_logger.error(f"Error in _on_center_and_fit: {e}", exc_info=True)
            self._show_error_message("Error", f"An unexpected error occurred: {e}")

    def _show_error_message(self, title: str, message: str):
        """
        Helper method to show an error message, typically delegated to MainWindow.
        This avoids direct dependency on tkinter.messagebox here.
        """
        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}")