# FlightMonitor/gui/panels/playback_panel.py
"""
Panel for controlling and viewing flight data playback.
"""
import tkinter as tk
from tkinter import ttk, font as tkFont, messagebox
from typing import Dict, Any, Optional, List
from datetime import datetime, timedelta, timezone

from flightmonitor.utils.logger import get_logger

module_logger = get_logger(__name__)


class PlaybackPanel:
    """
    Manages the UI for the Playback function tab, allowing users to select
    and control the playback of recorded flight data sessions.
    """

    def __init__(self, parent_frame: ttk.Frame, controller: Any):
        self.parent_frame = parent_frame
        self.controller = controller

        # --- Internal State ---
        self._session_data_map: Dict[str, Dict[str, Any]] = {}

        # --- Tkinter Variables ---
        self.selected_date_var = tk.StringVar()
        self.virtual_clock_var = tk.StringVar(value="--:--:--")
        self.playback_speed_var = tk.StringVar(value="1.0")
        self.timeline_var = tk.DoubleVar()

        # --- Widget References ---
        self.date_combobox: Optional[ttk.Combobox] = None
        self.sessions_treeview: Optional[ttk.Treeview] = None
        self.play_button: Optional[ttk.Button] = None
        self.pause_button: Optional[ttk.Button] = None
        self.stop_button: Optional[ttk.Button] = None
        self.timeline_slider: Optional[ttk.Scale] = None

        self._build_ui()
        module_logger.debug("PlaybackPanel initialized.")

    def _build_ui(self):
        """Builds all the widgets for the playback panel."""
        container = ttk.Frame(self.parent_frame, padding="10 10 10 10")
        container.pack(fill=tk.BOTH, expand=True)

        # --- Session Selection Frame ---
        session_frame = ttk.LabelFrame(
            container, text="Playback Session Selection", padding=10
        )
        session_frame.pack(fill=tk.X, expand=False, pady=(0, 10))
        session_frame.columnconfigure(1, weight=1)

        scan_button = ttk.Button(
            session_frame,
            text="Scan for Recordings",
            command=self._on_scan_for_recordings,
        )
        scan_button.grid(row=0, column=0, padx=(0, 5), sticky="w")

        self.date_combobox = ttk.Combobox(
            session_frame, textvariable=self.selected_date_var, state="readonly"
        )
        self.date_combobox.grid(row=0, column=1, columnspan=2, sticky="ew")
        self.date_combobox.bind("<<ComboboxSelected>>", self._on_date_selected)

        tree_frame = ttk.Frame(session_frame)
        tree_frame.grid(row=1, column=0, columnspan=3, sticky="nsew", pady=(10, 0))
        tree_frame.columnconfigure(0, weight=1)
        tree_frame.rowconfigure(0, weight=1)

        self.sessions_treeview = ttk.Treeview(
            tree_frame,
            columns=("start_time", "duration", "type", "area_description"),
            show="headings",
            height=5,
            selectmode="browse",
        )
        self.sessions_treeview.grid(row=0, column=0, sticky="nsew")

        self.sessions_treeview.heading("start_time", text="Start Time (UTC)")
        self.sessions_treeview.column("start_time", width=130, anchor=tk.W)
        self.sessions_treeview.heading("duration", text="Duration")
        self.sessions_treeview.column("duration", width=80, anchor=tk.CENTER)
        self.sessions_treeview.heading("type", text="Type")
        self.sessions_treeview.column("type", width=120, anchor=tk.W)
        self.sessions_treeview.heading("area_description", text="Area Description")
        self.sessions_treeview.column("area_description", width=150, stretch=True)

        scrollbar = ttk.Scrollbar(
            tree_frame, orient="vertical", command=self.sessions_treeview.yview
        )
        scrollbar.grid(row=0, column=1, sticky="ns")
        self.sessions_treeview.configure(yscrollcommand=scrollbar.set)

        # --- Playback Controls Frame ---
        controls_frame = ttk.LabelFrame(container, text="Playback Controls", padding=10)
        controls_frame.pack(fill=tk.BOTH, expand=True, pady=(10, 0))
        controls_frame.columnconfigure(1, weight=1)

        # Timeline and Clock
        clock_font = tkFont.Font(family="Courier New", size=14, weight="bold")
        virtual_clock_label = ttk.Label(
            controls_frame,
            textvariable=self.virtual_clock_var,
            font=clock_font,
            anchor="center",
        )
        virtual_clock_label.grid(row=0, column=0, columnspan=4, pady=(0, 5))

        self.timeline_slider = ttk.Scale(
            controls_frame,
            from_=0,
            to=100,
            orient="horizontal",
            variable=self.timeline_var,
            state=tk.DISABLED,
        )
        self.timeline_slider.grid(
            row=1, column=0, columnspan=4, sticky="ew", pady=(0, 10)
        )

        # Buttons and Speed Control
        button_frame = ttk.Frame(controls_frame)
        button_frame.grid(row=2, column=0, columnspan=4)

        self.play_button = ttk.Button(
            button_frame, text="▶ Play", command=self._on_play, state=tk.DISABLED
        )
        self.play_button.pack(side=tk.LEFT, padx=5)

        self.pause_button = ttk.Button(
            button_frame, text="❚❚ Pause", command=self._on_pause, state=tk.DISABLED
        )
        self.pause_button.pack(side=tk.LEFT, padx=5)

        self.stop_button = ttk.Button(
            button_frame, text="■ Stop", command=self._on_stop, state=tk.DISABLED
        )
        self.stop_button.pack(side=tk.LEFT, padx=5)

        ttk.Label(button_frame, text="Speed:").pack(side=tk.LEFT, padx=(15, 2))
        speed_options = ["0.5", "1.0", "2.0", "4.0", "8.0"]
        speed_combobox = ttk.Combobox(
            button_frame,
            textvariable=self.playback_speed_var,
            values=speed_options,
            width=5,
        )
        speed_combobox.pack(side=tk.LEFT)
        speed_combobox.bind("<<ComboboxSelected>>", self._on_speed_change)

    def _on_scan_for_recordings(self):
        self.update_available_dates()

    def update_available_dates(self):
        if not self.controller:
            return
        dates = self.controller.get_available_recording_dates()
        if self.date_combobox:
            self.date_combobox["values"] = dates
            if dates:
                self.selected_date_var.set(dates[0])
                self._on_date_selected()
            else:
                self.selected_date_var.set("")
                self._clear_sessions_treeview()
                self.play_button.config(state=tk.DISABLED)

    def _on_date_selected(self, event=None):
        date_str = self.selected_date_var.get()
        if date_str:
            self.update_sessions_for_date(date_str)

    def _clear_sessions_treeview(self):
        self._session_data_map.clear()
        if self.sessions_treeview:
            for item in self.sessions_treeview.get_children():
                self.sessions_treeview.delete(item)

    def update_sessions_for_date(self, date_str: str):
        self._clear_sessions_treeview()
        if not self.controller or not self.sessions_treeview:
            return

        sessions = self.controller.get_sessions_for_date(date_str)
        if not sessions:
            self.play_button.config(state=tk.DISABLED)
            return

        for session in sessions:
            scan_id = session.get("scan_id")
            if scan_id is None:
                continue

            self._session_data_map[str(scan_id)] = session
            try:
                start_ts = session.get("start_timestamp", 0)
                end_ts = session.get("end_timestamp", 0)

                start_dt = datetime.fromtimestamp(start_ts, timezone.utc)
                end_dt = datetime.fromtimestamp(end_ts, timezone.utc)

                duration_delta = end_dt - start_dt
                duration_str = str(duration_delta).split(".")[0]

                area_desc = (
                    f"BBox [{session.get('lat_min', 0):.2f}, {session.get('lon_min', 0):.2f}]"
                )

                self.sessions_treeview.insert(
                    "",
                    "end",
                    values=(
                        start_dt.strftime("%H:%M:%S"),
                        duration_str,
                        session.get("type", "Unknown"),
                        area_desc,
                    ),
                    iid=str(scan_id),
                )
            except Exception as e:
                module_logger.error(f"Failed to process session for display: {e}")
        
        # Select the first item by default and enable play button
        children = self.sessions_treeview.get_children()
        if children:
            self.sessions_treeview.selection_set(children[0])
            self.sessions_treeview.focus(children[0])
            self.play_button.config(state=tk.NORMAL)
        else:
            self.play_button.config(state=tk.DISABLED)

    def _on_play(self):
        if not self.controller or not self.sessions_treeview:
            return

        selected_items = self.sessions_treeview.selection()
        if not selected_items:
            messagebox.showwarning("No Selection", "Please select a session to play.", parent=self.parent_frame)
            return

        session_id = selected_items[0]
        session_info = self._session_data_map.get(session_id)
        
        if not session_info:
            messagebox.showerror("Error", "Could not find data for the selected session.", parent=self.parent_frame)
            return

        self.controller.start_playback(session_info)

    def _on_pause(self):
        if self.controller:
            self.controller.pause_playback()

    def _on_stop(self):
        if self.controller:
            self.controller.stop_playback()

    def _on_speed_change(self, event=None):
        if self.controller:
            try:
                speed = float(self.playback_speed_var.get())
                self.controller.set_playback_speed(speed)
            except (ValueError, TypeError):
                module_logger.warning("Invalid playback speed value.")

    def set_controls_state(self, is_playing: bool, is_paused: bool = False):
        if not self.parent_frame.winfo_exists():
            return
            
        # Controls disabled during playback
        scan_and_select_state = tk.DISABLED if is_playing else tk.NORMAL
        
        if self.date_combobox:
            self.date_combobox.config(state="readonly" if not is_playing else tk.DISABLED)
        # Also disable scan button and treeview
        # ... (assuming direct widget references or iterating children)

        if is_playing:
            if is_paused:
                self.play_button.config(state=tk.NORMAL, text="▶ Resume")
                self.play_button.configure(command=self._on_resume)
                self.pause_button.config(state=tk.DISABLED)
                self.stop_button.config(state=tk.NORMAL)
            else: # Playing
                self.play_button.config(state=tk.DISABLED, text="▶ Play")
                self.pause_button.config(state=tk.NORMAL)
                self.stop_button.config(state=tk.NORMAL)
        else: # Stopped
            self.play_button.config(state=tk.NORMAL, text="▶ Play")
            self.play_button.configure(command=self._on_play)
            self.pause_button.config(state=tk.DISABLED)
            self.stop_button.config(state=tk.DISABLED)

    def _on_resume(self):
        if self.controller:
            self.controller.resume_playback()
    
    def update_virtual_clock(self, timestamp: float):
        if not self.parent_frame.winfo_exists():
            return
        try:
            dt_object = datetime.fromtimestamp(timestamp, timezone.utc)
            self.virtual_clock_var.set(dt_object.strftime("%H:%M:%S"))
        except (ValueError, TypeError):
            self.virtual_clock_var.set("Invalid Time")

    def update_timeline(self, current_ts: float, start_ts: float, end_ts: float):
        if not self.parent_frame.winfo_exists() or not self.timeline_slider:
            return
            
        if (end_ts - start_ts) > 0:
            progress_percent = ((current_ts - start_ts) / (end_ts - start_ts)) * 100
            self.timeline_var.set(progress_percent)
        else:
            self.timeline_var.set(100)