from __future__ import annotations

from datetime import datetime
from typing import Any

from gi.repository import Gdk, Gtk, Pango

from .reactive import Watcher
from .video_player import VideoPlayer


class VideoOverlay(Gtk.Overlay, Watcher):
    player: VideoPlayer

    message: Gtk.Label
    message_expiration: float

    grid: Gtk.Grid
    grid_expiration: float

    clock_box: Gtk.Box
    clock: Gtk.Label

    now: float

    def __init__(self, player: VideoPlayer):
        super().__init__()

        self.now = 0.0
        self.player = player

        # Message is appears at the center of the screen,
        # above everything else. Usually to indicate change
        # of subtitle or audio track or something similar.
        self.message = Gtk.Label()
        self.message.set_name("overlay-message")
        self.message.set_valign(Gtk.Align.CENTER)
        self.message.set_halign(Gtk.Align.CENTER)
        self.message.set_visible(False)
        self.message.set_wrap(True)
        self.message.set_wrap_mode(Pango.WrapMode.WORD_CHAR)

        # Once specific time passes, message disappears.
        self.message_expiration = 0.0

        # Grid overlay is between the video at the bottom and
        # the message at the top. It is only shown when user
        # interacts with the player.
        self.grid = Gtk.Grid()
        self.grid.set_hexpand(True)
        self.grid.set_vexpand(True)
        self.grid.set_column_homogeneous(True)
        self.grid.set_row_homogeneous(True)

        # Grid visibility can also expire after a while.
        self.grid_expiration = 0.0

        # Create grid boxes.
        self.clock_box = Gtk.Box(hexpand=True, vexpand=True)
        self.grid.attach(self.clock_box, 0, 0, 1, 1)

        self.grid.attach(Gtk.Box(), 1, 0, 2, 1)
        self.grid.attach(Gtk.Box(), 0, 1, 3, 1)
        self.grid.attach(Gtk.Box(), 0, 2, 3, 1)

        # Add clock to the top-left grid box.
        self.clock = Gtk.Label(hexpand=True, vexpand=True)
        self.clock.set_name("overlay-clock")
        self.clock.set_halign(Gtk.Align.CENTER)
        self.clock.set_valign(Gtk.Align.START)
        self.clock.set_text(datetime.now().strftime("%H:%M"))
        self.clock_box.append(self.clock)

        # Add children.
        self.set_child(self.player.picture)
        self.add_overlay(self.grid)
        self.add_overlay(self.message)

        # Consume ticks for the clock and overlay expiration.
        self.add_tick_callback(self._on_tick, None)

        # Register all watches.
        self.watch_all()

    def _on_tick(self, widget: Gtk.Widget, frame_clock: Gdk.FrameClock, data: Any) -> bool:
        self.clock.set_text(datetime.now().strftime("%H:%M"))

        self.now = frame_clock.get_frame_time() / 1_000_000

        if self.grid_expiration <= self.now:
            self.grid.hide()

        if self.message_expiration <= self.now:
            self.message.hide()

        return True

    def show_message(self, text: str, timeout: float = 1.0) -> None:
        """Show text in a centered overlay that disappears after timeout."""

        self.message.set_text(text)
        self.message.show()
        self.message_expiration = self.now + timeout

    def _watch_player_state(self):
        is_playing = self.player.is_playing.value
        is_paused = self.player.is_paused.value

        if is_playing and is_paused:
            self.grid.show()
            self.grid_expiration = 1e20
        else:
            self.grid_expiration = 0