from __future__ import annotations

import ctypes
from queue import Queue

from r36s_dlna_browser.dlna.browser_state import BrowserState
from r36s_dlna_browser.platform.controls import Action
from r36s_dlna_browser.ui import theme
from r36s_dlna_browser.ui import sdl_app as sdl_app_module
from r36s_dlna_browser.ui.sdl_app import SDLApp, Screen


class DummyPlayer:
    def __init__(self) -> None:
        self._new_frame = False
        self.viewport = None

    def attach_window(self, _window) -> None:
        pass

    def set_viewport(self, *args) -> None:
        self.viewport = args

    def has_new_frame(self) -> bool:
        return self._new_frame

    def render(self, _renderer) -> bool:
        self._new_frame = False
        return True


def _make_app() -> SDLApp:
    return SDLApp(Queue(), Queue(), BrowserState(), DummyPlayer())


def test_non_playback_draws_only_when_dirty() -> None:
    app = _make_app()
    app._screen = Screen.SERVERS
    app._needs_redraw = False

    assert app._should_draw() is False

    app._mark_dirty()

    assert app._should_draw() is True


def test_playback_snapshot_change_waits_for_refresh_interval(monkeypatch) -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    app._needs_redraw = False
    app._last_playback_snapshot = app._playback_snapshot()
    app._last_playback_draw_at = 10.0
    app._state.playback_position = 1.0

    monkeypatch.setattr(sdl_app_module.time, "monotonic", lambda: 10.1)

    assert app._should_draw() is False


def test_playback_snapshot_change_redraws_after_refresh_interval(monkeypatch) -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    app._needs_redraw = False
    app._last_playback_snapshot = app._playback_snapshot()
    app._last_playback_draw_at = 10.0
    app._state.playback_position = 1.0

    monkeypatch.setattr(sdl_app_module.time, "monotonic", lambda: 10.3)

    assert app._should_draw() is True


def test_playback_snapshot_without_changes_does_not_redraw(monkeypatch) -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    app._needs_redraw = False
    app._last_playback_snapshot = app._playback_snapshot()
    app._last_playback_draw_at = 10.0

    monkeypatch.setattr(sdl_app_module.time, "monotonic", lambda: 10.5)

    assert app._should_draw() is False


def test_playback_draws_immediately_for_new_video_frame() -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    app._needs_redraw = False
    app._player._new_frame = True

    assert app._should_draw() is True


def test_hud_mode_cycles_auto_fixed_hidden(monkeypatch) -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    monkeypatch.setattr(sdl_app_module.time, "monotonic", lambda: 12.0)

    app._handle_action(Action.HUD_MODE)
    assert app._state.playback_hud_mode == theme.PLAYBACK_HUD_PINNED
    assert app._state.playback_hud_visible is True

    app._handle_action(Action.HUD_MODE)
    assert app._state.playback_hud_mode == theme.PLAYBACK_HUD_HIDDEN
    assert app._state.playback_hud_visible is False

    app._handle_action(Action.HUD_MODE)
    assert app._state.playback_hud_mode == theme.PLAYBACK_HUD_AUTO
    assert app._state.playback_hud_visible is True


def test_paused_playback_keeps_hud_visible_in_auto_mode(monkeypatch) -> None:
    app = _make_app()
    app._screen = Screen.PLAYBACK
    app._state.playback_hud_mode = theme.PLAYBACK_HUD_AUTO
    app._state.playback_hud_visible = False
    app._state.playback_paused = True

    monkeypatch.setattr(sdl_app_module.time, "monotonic", lambda: 99.0)

    app._refresh_playback_hud_visibility()

    assert app._state.playback_hud_visible is True


def test_layout_scales_for_square_display() -> None:
    compact = theme.get_layout(640, 480)
    square = theme.get_layout(720, 720)

    assert square.visible_items > compact.visible_items
    assert square.list_item_h > compact.list_item_h
    assert square.playback_hud_top > compact.playback_hud_top


def test_sync_player_viewport_uses_runtime_layout(monkeypatch) -> None:
    app = _make_app()
    app._window = object()

    def fake_get_window_size(_window, width_ptr, height_ptr):
        width = ctypes.cast(width_ptr, ctypes.POINTER(ctypes.c_int))
        height = ctypes.cast(height_ptr, ctypes.POINTER(ctypes.c_int))
        width.contents.value = 720
        height.contents.value = 720

    monkeypatch.setattr(sdl_app_module.sdl2, "SDL_GetWindowSize", fake_get_window_size)

    app._sync_player_viewport()

    layout = app._layout
    assert layout.width == 720
    assert layout.height == 720
    assert app._player.viewport == (
        720,
        720,
        layout.playback_hud_top,
        720 - layout.playback_video_bottom,
        layout.playback_video_left,
        720 - layout.playback_video_right,
    )