# FlightMonitor/controller/playback_data_processor.py
"""
Manages the processing of playback data from the PlaybackAdapter's output queue.
It updates the GUI's virtual clock, timeline, and dispatches flight states to the map.
"""
from queue import Queue, Empty as QueueEmpty
from typing import Optional, TYPE_CHECKING
import time

from flightmonitor.utils.logger import get_logger
from flightmonitor.data.data_constants import (
    MSG_TYPE_FLIGHT_DATA,
    MSG_TYPE_ADAPTER_STATUS,
    STATUS_STOPPED,
)
from flightmonitor.data.common_models import CanonicalFlightState

if TYPE_CHECKING:
    from flightmonitor.controller.app_controller import AppController

module_logger = get_logger(__name__)

GUI_QUEUE_CHECK_INTERVAL_MS = 100


class PlaybackDataProcessor:
    """
    Processes flight data snapshots from a queue for playback, updating the GUI
    (virtual clock, map, timeline slider) for each snapshot.
    """

    def __init__(
        self, app_controller: "AppController", data_queue: Queue
    ):
        """
        Initializes the PlaybackDataProcessor.

        Args:
            app_controller: The main AppController instance.
            data_queue: The queue from which to read playback data snapshots.
        """
        self.app_controller = app_controller
        self.data_queue = data_queue
        self._gui_after_id: Optional[str] = None
        module_logger.debug("PlaybackDataProcessor initialized.")

    def start_processing(self):
        """Starts the periodic processing of the playback data queue."""
        main_window = self.app_controller.main_window
        if not (main_window and main_window.root and main_window.root.winfo_exists()):
            module_logger.error(
                "PlaybackDataProcessor: Cannot start queue processing, MainWindow or root is missing."
            )
            return

        if self._gui_after_id:
            try:
                main_window.root.after_cancel(self._gui_after_id)
            except Exception:
                pass

        module_logger.info(
            "PlaybackDataProcessor: Starting playback data queue processing loop."
        )
        self._gui_after_id = main_window.root.after(
            GUI_QUEUE_CHECK_INTERVAL_MS, self._process_queue_cycle
        )

    def stop_processing(self):
        """Stops the periodic processing loop."""
        main_window = self.app_controller.main_window
        if self._gui_after_id and main_window and main_window.root.winfo_exists():
            try:
                main_window.root.after_cancel(self._gui_after_id)
                module_logger.info(
                    "PlaybackDataProcessor: Stopped queue processing loop."
                )
            except Exception:
                pass
            finally:
                self._gui_after_id = None

        if self.data_queue:
            while not self.data_queue.empty():
                try:
                    self.data_queue.get_nowait()
                except QueueEmpty:
                    break

    def _process_queue_cycle(self):
        """
        The core processing cycle that runs on the GUI thread.
        It retrieves a data snapshot, updates the clock, and updates the map.
        """
        main_window = self.app_controller.main_window

        if not (main_window and main_window.root and main_window.root.winfo_exists()):
            self._gui_after_id = None
            return

        try:
            message = self.data_queue.get_nowait()
            message_type = message.get("type")

            if message_type == MSG_TYPE_FLIGHT_DATA:
                snapshot_timestamp = message.get("timestamp")
                payload_dict = message.get("payload", {})
                flight_states: List[CanonicalFlightState] = payload_dict.get(
                    "canonical", []
                )

                playback_panel = (
                    main_window.function_notebook_panel.playback_panel
                    if hasattr(main_window.function_notebook_panel, "playback_panel")
                    else None
                )
                
                if snapshot_timestamp and playback_panel:
                    playback_panel.update_virtual_clock(snapshot_timestamp)
                    if self.app_controller.playback_adapter_thread:
                        start_ts = self.app_controller.playback_adapter_thread.start_ts
                        end_ts = self.app_controller.playback_adapter_thread.end_ts
                        playback_panel.update_timeline(snapshot_timestamp, start_ts, end_ts)

                if main_window.map_manager_instance:
                    main_window.map_manager_instance.update_playback_frame(
                        flight_states, snapshot_timestamp
                    )

            elif message_type == MSG_TYPE_ADAPTER_STATUS:
                if message.get("status_code") == STATUS_STOPPED:
                    module_logger.info(
                        "Playback adapter finished. Stopping playback from processor."
                    )
                    self.app_controller.stop_playback(finished_normally=True)

            self.data_queue.task_done()

        except QueueEmpty:
            pass
        except Exception as e:
            module_logger.error(f"Error in PlaybackDataProcessor cycle: {e}", exc_info=True)
            self.app_controller.stop_playback(from_error=True)

        if self.app_controller.is_playback_active:
            if main_window and main_window.root and main_window.root.winfo_exists():
                self._gui_after_id = main_window.root.after(
                    GUI_QUEUE_CHECK_INTERVAL_MS, self._process_queue_cycle
                )
            else:
                self._gui_after_id = None
        else:
            self._gui_after_id = None