"""
Display & Sound — the everyday device levels + presentation, plus a door to Power.

The R36S has ONE built-in screen and NO video output, so there's nothing to
"switch to". This screen holds the everyday stuff, in plain language:

  Brightness — a real slider (the ONE backlight, also in the Quick Menu).
  Volume     — a real slider (the ONE ALSA level, also in the Quick Menu).
               Lives here now, not buried under Bluetooth — BT keeps only the
               audio ROUTE / mute / test-tone.
  Look       — Crisp (sharp, pixel-correct) or Retro (authentic per-system
               filter, the §12 default). The smart per-system mapping is under
               the hood in gui.library.display; no shader filenames here.
  Power      — a row that opens the Power module (this screen is also the
               Power hub; Power has no Home tile of its own).

  status bar : back chevron + "Display & Sound"
  hero       : eyebrow + one-line subtitle
  brightness : labelled slider (←/→ adjust, writes the real backlight live)
  volume     : labelled slider (←/→ adjust, writes the real ALSA level live)
  picker     : 2-segment Crisp / Retro (←/→ choose + apply, persists)
  promise    : the selected look's plain-English one-liner
  power      : "Power & performance" row (A opens P1Profiles)
  footer     : ←/→ adjust/choose · A apply/open · B back

Up/Down is a single cursor across the four zones (brightness → volume → look
→ power).
"""

from __future__ import annotations

import pygame

from ..design import tokens as t
from ..shared import widgets as w
from ..shared import fonts, icons, render
from ..shared import backend
from ...library import display as display_mod

SAFE = t.Space.SAFE_AREA
STAGE_W = t.VIEWPORT_WIDTH
STAGE_H = t.VIEWPORT_HEIGHT
BODY_TOP = t.Space.STATUS_BAR_HEIGHT
BODY_BOTTOM = STAGE_H - t.Space.FOOTER_HINT_HEIGHT


# Focusable zones (top → bottom), navigated by Up/Down.
Z_BRIGHT = 0
Z_VOLUME = 1
Z_LOOK = 2
Z_POWER = 3

# Look catalog — display order is the "retro intensity" ladder (sharp → full).
_LOOKS = [
    (display_mod.LOOK_CRISP, "Crisp", "Sharp, pixel-correct — no filter."),
    (display_mod.LOOK_RETRO, "Retro", "Each system the way it looked — CRT or LCD."),
]
_DEFAULT_SEL = len(_LOOKS) - 1            # Retro, if the saved value is unknown

_BRIGHT_MIN = 5                           # never let the slider black out the panel
_STEP = 5

# Vertical anchors (BODY_TOP-relative).
BRIGHT_Y = BODY_TOP + 54
VOLUME_Y = BODY_TOP + 100
LEVEL_H = 42
PICKER_Y = BODY_TOP + 148
PICKER_H = 42
DESC_Y = PICKER_Y + PICKER_H + 12
POWER_ROW_Y = BODY_TOP + 220
POWER_ROW_H = 40


class DisplayScreen:
    name = "display"

    def __init__(self, app):
        self.app = app
        look = app.library.play_state().display_look()    # crisp | retro
        self.sel = self._index_of(look)
        b = backend.display_brightness()                  # 0..100 live, or None
        self.bright = b if b is not None else 70          # calm demo off-device
        v = backend.volume_get()
        self.vol = v if v is not None else 60
        self.focus = Z_BRIGHT

    @staticmethod
    def _index_of(look: str) -> int:
        return next((i for i, (k, _, _) in enumerate(_LOOKS) if k == look),
                    _DEFAULT_SEL)

    # ── input ────────────────────────────────────────────────────────
    def on_action(self, action):
        if action == "b":
            self.app.pop()
            return
        if action == "a":
            if self.focus == Z_LOOK:
                self._apply_look()
            elif self.focus == Z_POWER:
                from .power import P1Profiles
                self.app.push(P1Profiles(self.app))
        elif action == "left":
            if self.focus in (Z_BRIGHT, Z_VOLUME):
                self._nudge(-_STEP)
            elif self.focus == Z_LOOK and self.sel > 0:
                self.sel -= 1
                self._apply_look()
        elif action == "right":
            if self.focus in (Z_BRIGHT, Z_VOLUME):
                self._nudge(+_STEP)
            elif self.focus == Z_LOOK and self.sel < len(_LOOKS) - 1:
                self.sel += 1
                self._apply_look()
        elif action == "down":
            self.focus = min(Z_POWER, self.focus + 1)
        elif action == "up":
            self.focus = max(Z_BRIGHT, self.focus - 1)

    def _nudge(self, delta):
        if self.focus == Z_BRIGHT:
            self.bright = max(_BRIGHT_MIN, min(100, self.bright + delta))
            backend.display_set_brightness(self.bright)   # live; None off-device
        else:                                             # Z_VOLUME (mute at 0 is fine)
            self.vol = max(0, min(100, self.vol + delta))
            backend.volume_set(self.vol)

    def _apply_look(self):
        key, label, _ = _LOOKS[self.sel]
        applied = self.app.library.play_state().set_display_look(key)
        self.sel = self._index_of(applied)            # reflect what persisted
        self.app.toast(f"Look: {label}")

    def update(self, dt_ms):
        pass

    # ── draw ─────────────────────────────────────────────────────────
    def draw(self, surf):
        surf.fill(t.Color.BG_DEEP)
        self._draw_status(surf)
        self._draw_hero(surf)
        self._draw_level(surf, BRIGHT_Y, "ph-lightbulb", "Brightness",
                         self.bright, self.focus == Z_BRIGHT)
        self._draw_level(surf, VOLUME_Y, "ph-speaker-high", "Volume",
                         self.vol, self.focus == Z_VOLUME)
        self._draw_picker(surf)
        self._draw_promise(surf)
        self._draw_power_row(surf)
        self._draw_footer(surf)

    def _draw_status(self, surf):
        bar = pygame.Rect(0, 0, STAGE_W, BODY_TOP)
        pygame.draw.rect(surf, t.Color.BG_DEEP, bar)
        pygame.draw.line(surf, t.with_alpha(t.Color.TEXT_PRIMARY, 0.06),
                         (0, BODY_TOP), (STAGE_W, BODY_TOP), 1)
        chev = icons.icon("ph-caret-left", 14, t.Color.TEXT_SECONDARY)
        surf.blit(chev, (12, BODY_TOP // 2 - 7))
        title = fonts.render(t.Type.TITLE, "Display & Sound", t.Color.TEXT_PRIMARY)
        surf.blit(title, (32, BODY_TOP // 2 - title.get_height() // 2))

    def _draw_hero(self, surf):
        y = BODY_TOP + 12
        eye = fonts.render(t.Type.EYEBROW, "EVERYDAY", t.Color.ACCENT_PEACH,
                           upper=True)
        surf.blit(eye, (SAFE, y))
        line = fonts.render(t.Type.CAPTION,
                            "Brightness, volume, and how each system looks.",
                            t.Color.TEXT_SECONDARY)
        surf.blit(line, (SAFE, y + 18))

    def _draw_level(self, surf, y, icon_name, label, value, focused):
        """A labelled slider row (brightness / volume). ←/→ adjust; focus =
        elevated body + glow + gradient border."""
        rect = pygame.Rect(SAFE, y, STAGE_W - 2 * SAFE, LEVEL_H)
        c0, c1 = ((t.Color.SURFACE_ELEVATED, t.Color.SURFACE_BASE) if focused
                  else (t.Color.SURFACE_BASE, t.Color.BG_MID))
        body = render.rounded_gradient((rect.w, rect.h), c0, c1, t.Radius.BUTTON, 160)
        if not focused:
            pygame.draw.rect(body, t.Color.BORDER_SOFT, (0, 0, rect.w, rect.h),
                             width=1, border_radius=t.Radius.BUTTON)
        icol = t.Color.ACCENT_PEACH if focused else t.Color.TEXT_SECONDARY
        body.blit(icons.icon(icon_name, 20, icol), (16, (rect.h - 20) // 2))
        lab = fonts.render(t.Type.BODY_STRONG, label, t.Color.TEXT_PRIMARY)
        body.blit(lab, (16 + 20 + 12, (rect.h - lab.get_height()) // 2))
        val = fonts.render(t.Type.BODY_STRONG, f"{value}%", t.Color.TEXT_PRIMARY)
        body.blit(val, (rect.w - 16 - val.get_width(), (rect.h - val.get_height()) // 2))
        sx = 16 + 20 + 12 + lab.get_width() + 18
        sw = (rect.w - 16 - val.get_width() - 14) - sx
        if sw > 24:
            w.slider(body, sx, rect.h // 2 - 3, sw, value / 100)

        if focused:
            glow, gpos = render.focus_glow(rect, t.Radius.BUTTON)
            surf.blit(glow, gpos)
        surf.blit(body, rect.topleft)
        if focused:
            surf.blit(render.gradient_border((rect.w, rect.h), t.Radius.BUTTON),
                      rect.topleft)

    def _draw_picker(self, surf):
        """2-segment look picker. ←/→ moves the selection (and applies it);
        the whole bar carries the focus border when this zone is focused."""
        bar = pygame.Rect(SAFE, PICKER_Y, STAGE_W - 2 * SAFE, PICKER_H)
        focused = (self.focus == Z_LOOK)
        n = len(_LOOKS)
        seg_w = bar.w // n

        bg = pygame.Surface((bar.w, bar.h), pygame.SRCALPHA)
        pygame.draw.rect(bg, t.with_alpha(t.Color.TEXT_PRIMARY, 0.05),
                         (0, 0, bar.w, bar.h), border_radius=10)
        pygame.draw.rect(bg, t.with_alpha(t.Color.TEXT_PRIMARY, 0.08),
                         (0, 0, bar.w, bar.h), width=1, border_radius=10)
        ax = self.sel * seg_w
        pygame.draw.rect(bg, t.with_alpha(t.Color.ACCENT_PEACH, 0.18),
                         (ax + 3, 3, seg_w - 6, bar.h - 6), border_radius=8)
        for i, (_key, label, _desc) in enumerate(_LOOKS):
            col = t.Color.TEXT_PRIMARY if i == self.sel else t.Color.TEXT_MUTED
            lab = fonts.render(t.Type.BODY_STRONG, label, col)
            sx = i * seg_w + (seg_w - lab.get_width()) // 2
            bg.blit(lab, (sx, bar.h // 2 - lab.get_height() // 2))

        if focused:
            glow, gpos = render.focus_glow(bar, 10)
            surf.blit(glow, gpos)
        surf.blit(bg, bar.topleft)
        if focused:
            surf.blit(render.gradient_border((bar.w, bar.h), 10), bar.topleft)

    def _draw_promise(self, surf):
        _, _, desc = _LOOKS[self.sel]
        line = fonts.render(t.Type.BODY_SM, desc, t.Color.TEXT_SECONDARY)
        surf.blit(line, ((STAGE_W - line.get_width()) // 2, DESC_Y))

    def _draw_power_row(self, surf):
        rect = pygame.Rect(SAFE, POWER_ROW_Y, STAGE_W - 2 * SAFE, POWER_ROW_H)
        w.list_row(surf, rect, "Power & performance",
                   "ph-battery-charging-vertical",
                   focused=(self.focus == Z_POWER))

    def _draw_footer(self, surf):
        if self.focus == Z_POWER:
            hints = [("A", "Open"), ("B", "Back")]
        elif self.focus == Z_LOOK:
            hints = [("A", "Apply"), ("B", "Back")]
        else:                                          # brightness / volume
            hints = [("B", "Back")]
        w.footer_hints(surf, hints)
