"""Navigation stack, pagination and in-memory cache for the browser."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import List, Optional

from r36s_dlna_browser.dlna.models import MediaServer, MediaItem
from r36s_dlna_browser.ui import theme


@dataclass
class _Level:
    """One level of the navigation stack."""
    server_location: str
    object_id: str
    items: List[MediaItem] = field(default_factory=list)
    cursor: int = 0
    scroll_offset: int = 0


class BrowserState:
    """Tracks the server list, the current navigation stack and cursor position."""

    def __init__(self) -> None:
        self.servers: List[MediaServer] = []
        self.server_cursor: int = 0
        self.server_scroll_offset: int = 0

        self._stack: List[_Level] = []

        self.loading: bool = False
        self.error: str = ""
        self.playback_title: str = ""
        self.playback_paused: bool = False
        self.playback_position: float = 0.0
        self.playback_duration: float = 0.0
        self.playback_volume: int = 100
        self.playback_cache_seconds: float = 0.0
        self.playback_buffer_percent: int = 0
        self.playback_resolution: str = ""
        self.playback_hud_visible: bool = True
        self.playback_hud_mode: int = theme.PLAYBACK_HUD_AUTO
        self.playback_backend: str = "gstreamer-sdl"
        self.playback_video_driver: str = ""

    # ── server list ──────────────────────────────────────────────

    def set_servers(self, servers: List[MediaServer]) -> None:
        self.servers = servers
        self.server_cursor = 0
        self.server_scroll_offset = 0

    @property
    def selected_server(self) -> Optional[MediaServer]:
        if 0 <= self.server_cursor < len(self.servers):
            return self.servers[self.server_cursor]
        return None

    # ── browse stack ─────────────────────────────────────────────

    @property
    def in_browse_mode(self) -> bool:
        return len(self._stack) > 0

    @property
    def current_level(self) -> Optional[_Level]:
        return self._stack[-1] if self._stack else None

    @property
    def current_items(self) -> List[MediaItem]:
        lv = self.current_level
        return lv.items if lv else []

    @property
    def cursor(self) -> int:
        lv = self.current_level
        return lv.cursor if lv else 0

    @cursor.setter
    def cursor(self, value: int) -> None:
        lv = self.current_level
        if lv:
            lv.cursor = max(0, min(value, len(lv.items) - 1)) if lv.items else 0

    @property
    def scroll_offset(self) -> int:
        lv = self.current_level
        return lv.scroll_offset if lv else 0

    @scroll_offset.setter
    def scroll_offset(self, value: int) -> None:
        lv = self.current_level
        if lv:
            lv.scroll_offset = value

    def selected_item(self) -> Optional[MediaItem]:
        items = self.current_items
        c = self.cursor
        if 0 <= c < len(items):
            return items[c]
        return None

    def set_items(self, items: List[MediaItem], object_id: str) -> None:
        """Push or update items for the given object_id."""
        lv = self.current_level
        if lv and lv.object_id == object_id:
            lv.items = items
            lv.cursor = 0
            lv.scroll_offset = 0
        else:
            # Find server_location from the stack or current server
            loc = ""
            if self._stack:
                loc = self._stack[-1].server_location
            elif self.selected_server:
                loc = self.selected_server.location
            self._stack.append(_Level(
                server_location=loc,
                object_id=object_id,
                items=items,
            ))

    def go_back(self) -> bool:
        """Pop one level.  Returns True if we went back, False if at root."""
        if self._stack:
            self._stack.pop()
            return True
        return False

    def enter_server(self, server: MediaServer) -> str:
        """Start browsing a server.  Returns the root object_id."""
        self._stack.clear()
        self._stack.append(_Level(
            server_location=server.location, object_id="0"
        ))
        return "0"

    def reset(self) -> None:
        self._stack.clear()
        self.error = ""
        self.playback_title = ""
        self.playback_paused = False
        self.playback_position = 0.0
        self.playback_duration = 0.0
        self.playback_cache_seconds = 0.0
        self.playback_buffer_percent = 0
        self.playback_resolution = ""
        self.playback_hud_visible = True
        self.playback_hud_mode = theme.PLAYBACK_HUD_AUTO
