# display.py
"""
This module manages the display of images using OpenCV.
It handles window creation, image updates, and mouse event callbacks.
"""

import cv2
import logging
import numpy as np
import config # Import the config module
import queue # Import the queue module

class DisplayManager:
    """
    A class to manage the display of images using OpenCV.
    """
    def __init__(self, app, sar_queue, mouse_queue, sar_x, sar_y, mfd_x, mfd_y):
        """
        Initializes the DisplayManager.

        Args:
            app (App): The main application instance.
            sar_queue (queue.Queue): The queue for SAR images.
            mouse_queue (queue.Queue): The queue for mouse coordinates.
            sar_x (int): The x-coordinate of the SAR window.
            sar_y (int): The y-coordinate of the SAR window.
            mfd_x (int): The x-coordinate of the MFD window.
            mfd_y (int): The y-coordinate of the MFD window.
        """
        self.app = app
        self.sar_queue = sar_queue
        self.mouse_queue = mouse_queue
        self.sar_x = sar_x
        self.sar_y = sar_y
        self.mfd_x = mfd_x
        self.mfd_y = mfd_y
        self.sar_window_initialized = False
        self.mfd_window_initialized = False
        self.sar_mouse_callback_set = False # Flag to track if the callback has been set
        self.last_mouse_update = 0 # Last time the mouse position was updated

    def show_mfd_image(self, image):
        """
        Displays the MFD image in an OpenCV window.

        Args:
            image (numpy.ndarray): The MFD image to display.
        """
        try:
            # Create and move window only once
            if not self.mfd_window_initialized:
                cv2.imshow("MFD", image)
                try:
                    cv2.moveWindow("MFD", self.mfd_x, self.mfd_y)
                    self.mfd_window_initialized = True
                except cv2.error as e:
                    print(f"Error moving MFD window on initialization: {e}")
                    logging.error(f"Error moving MFD window on initialization: {e}")
            else:
                cv2.imshow("MFD", image)  # Just update the image
        except Exception as e:
            print(f"Error displaying MFD image: {e}")
            logging.exception(f"Error displaying MFD image: {e}")

    def show_sar_image(self, image):
        """
        Displays the SAR image in an OpenCV window.

        Args:
            image (numpy.ndarray): The SAR image to display.
        """
        if image is None or not isinstance(image, np.ndarray) or image.size == 0 or image.shape[0] == 0 or image.shape[1] == 0:
            print("Error: Invalid SAR image dimensions. Skipping display.")
            logging.error("Error: Invalid SAR image dimensions. Skipping display.")
            return # Skip

        try:
            # Create and move window only once
            if not self.sar_window_initialized:
                cv2.imshow("SAR", image)
                try:
                    cv2.moveWindow("SAR", self.sar_x, self.sar_y)
                    self.sar_window_initialized = True
                except cv2.error as e:
                    print(f"Error moving SAR window on initialization: {e}")
                    logging.error(f"Error moving SAR window on initialization: {e}")

                # Set mouse callback *after* the window is created
                cv2.setMouseCallback("SAR", self.sar_mouse_callback)
                self.sar_mouse_callback_set = True

            else:
                cv2.imshow("SAR", image)  # Just update the image
        except Exception as e:
            print(f"Error displaying SAR image: {e}")
            logging.exception(f"Error displaying SAR image: {e}")

    def sar_mouse_callback(self, event, x, y, flags, param):
        """
        Callback function for mouse events on the SAR window.
        Calculates the latitude and longitude based on the mouse coordinates and puts them in the queue.

        Args:
            event (int): The type of mouse event.
            x (int): The x-coordinate of the mouse pointer.
            y (int): The y-coordinate of the mouse pointer.
            flags (int): Any flags passed by the event.
            param (None): Any extra parameters passed by the event.
        """
        if event == cv2.EVENT_MOUSEMOVE:
            # Convert pixel coordinates to normalized coordinates (0.0 - 1.0)
            normalized_x = x / self.app.sar_display_width
            normalized_y = y / self.app.sar_display_height

            # Convert normalized coordinates to kilometers from the center
            km_x = (normalized_x - 0.5) * config.SAR_IMAGE_SIZE_KM
            km_y = (0.5 - normalized_y) * config.SAR_IMAGE_SIZE_KM  # Y axis is inverted

            # Convert kilometers to latitude and longitude offset
            lat_offset = km_y / 111.0  # Approximate km to latitude conversion
            lon_offset = km_x / (111.0 * np.cos(np.radians(config.SAR_CENTER_LAT)))  # Approximate km to longitude

            # Calculate latitude and longitude
            latitude = config.SAR_CENTER_LAT + lat_offset
            longitude = config.SAR_CENTER_LON + lon_offset

            # Put the coordinates in the queue
            try:
                self.sar_queue.put((latitude, longitude), block=False)
            except queue.Full:
                pass  # Drop value

    def process_sar_queue(self):
        """
        This function get the new Sar image from queue and displays
        """
        try:
            image = self.sar_queue.get(block=False)
            if isinstance(image, np.ndarray):
                self.show_sar_image(image)
        except queue.Empty:
            pass

    def process_mouse_queue(self):
        """Processes the mouse coordinate queue and updates the Tkinter label."""
        try:
            latitude, longitude = self.mouse_queue.get(block=False)
            # Limit the update rate to 10 times per second (100 ms interval)
            current_time = time.time()
            if current_time - self.last_mouse_update >= 0.1:
                self.app.update_mouse_latlon_label(latitude, longitude)
                self.last_mouse_update = current_time
        except queue.Empty:
            pass