"""
Splash / boot screen.

Drawn as the very first pygame frame (before the heavier background + home
build) so the user never stares at a black frame while AAhead spins up.
Self-contained: paints its own background.

The static composition (rings · halo · wordmark · divider · tagline ·
meta) is rendered ONCE into a cached surface; only the 3-dot pulse loader
animates per frame, so the boot hold-loop stays cheap on the RK3326.

Composition is from the Splash.html handoff.
"""

from __future__ import annotations

import math

import pygame

from ..design import tokens as t
from ..shared import widgets as w
from ..shared import fonts, render

CX, CY = 320, 200          # ring + lockup center (~42% of 480)
VERSION = "v 1.4.0"
DEVICE = "R36S · dArkOSRE"


class SplashScreen:
    name = "splash"

    def __init__(self, app=None):
        self.app = app
        self.elapsed = 0.0
        self._static = self._build_static()

    def on_action(self, action):
        if action in ("a", "b", "start") and self.app is not None:
            self.app.pop()

    def update(self, dt_ms):
        self.elapsed += dt_ms

    def draw(self, surf):
        surf.blit(self._static, (0, 0))
        self._draw_loader(surf, CX, 424)

    # ── static composition (built once) ─────────────────────────────────
    def _build_static(self) -> pygame.Surface:
        s = pygame.Surface((640, 480)).convert()
        s.fill(t.hex_rgb("#07050E"))
        s.blit(render.radial_gradient((640, 480), (0.5, 0.42),
                                      t.Color.BG_UP, t.Color.BG_DEEP).convert(), (0, 0))
        halo = _build_halo()
        s.blit(halo, (CX - halo.get_width() // 2, CY - halo.get_height() // 2))
        self._draw_rings(s)

        # center lockup: AAhead Control wordmark (64 / 42)
        big = t.TextStyle(t.SPACE_GROTESK_BOLD, 64, "Bold", -2)
        ctl = t.TextStyle(t.SPACE_GROTESK_SEMIBOLD, 42, "SemiBold", -1)
        aa = w.gradient_text(big, "AA")
        head = fonts.render(big, "head", t.Color.TEXT_PRIMARY)
        ctrl = fonts.render(ctl, "Control", t.Color.TEXT_SECONDARY)
        gap = 16
        base = max(aa.get_height(), head.get_height())
        lock_w = aa.get_width() + head.get_width() + gap + ctrl.get_width()
        lx = CX - lock_w // 2
        ly = CY - base // 2 - 18
        s.blit(aa, (lx, ly)); lx += aa.get_width()
        s.blit(head, (lx, ly)); lx += head.get_width() + gap
        s.blit(ctrl, (lx, ly + base - ctrl.get_height() - 4))

        div_y = ly + base + 20
        self._draw_divider(s, CX, div_y, 80)
        self._draw_tagline(s, CX, div_y + 16)

        ver = fonts.render(t.Type.META_SM, VERSION, t.Color.TEXT_DISABLED)
        s.blit(ver, (16, 480 - 14 - ver.get_height()))
        dev = fonts.render(t.Type.META_SM, DEVICE, t.Color.TEXT_DISABLED)
        s.blit(dev, (640 - 16 - dev.get_width(), 480 - 14 - dev.get_height()))
        return s

    def _draw_rings(self, surf):
        layer = pygame.Surface((640, 480), pygame.SRCALPHA)
        for r, col, a in ((170, t.Color.ACCENT_CYAN, 26),
                          (140, t.Color.ACCENT_ROSE, 30),
                          (76, t.Color.ACCENT_CYAN, 40)):
            pygame.draw.circle(layer, (*col, a), (CX, CY), r, 1)
        for i in range(0, 360, 6):                 # dashed gradient mid-ring
            ang = math.radians(i)
            col = render._lerp(t.Color.ACCENT_ROSE, t.Color.ACCENT_CYAN, i / 360.0)
            px = CX + 108 * math.cos(ang); py = CY + 108 * math.sin(ang)
            pygame.draw.circle(layer, (*col, 130), (int(px), int(py)), 1)
        for dx, dy in ((0, -1), (0, 1), (-1, 0), (1, 0)):   # compass ticks
            pygame.draw.line(layer, (*t.Color.ACCENT_ROSE, 110),
                             (CX + dx * 174, CY + dy * 174),
                             (CX + dx * 182, CY + dy * 182), 1)
        surf.blit(layer, (0, 0))

    def _draw_divider(self, surf, cx, y, width):
        grad = render.linear_gradient((width, 1), t.Color.ACCENT_ROSE,
                                      t.Color.ACCENT_CYAN, 90).convert_alpha()
        for x in range(width):
            edge = min(x, width - 1 - x) / (width / 2)
            grad.set_at((x, 0), (*grad.get_at((x, 0))[:3], int(140 * min(1.0, edge))))
        surf.blit(grad, (cx - width // 2, y))

    def _draw_tagline(self, surf, cx, y):
        a = fonts.render(t.Type.CAPTION, "For the handhelds you actually ",
                         t.Color.TEXT_SECONDARY)
        b = fonts.render(t.Type.CAPTION, "love", t.Color.TEXT_PRIMARY)
        c = fonts.render(t.Type.CAPTION, ".", t.Color.TEXT_SECONDARY)
        x = cx - (a.get_width() + b.get_width() + c.get_width()) // 2
        surf.blit(a, (x, y)); x += a.get_width()
        surf.blit(b, (x, y)); x += b.get_width()
        surf.blit(c, (x, y))

    # ── animated loader (per frame) ──────────────────────────────────────
    def _draw_loader(self, surf, cx, y):
        cols = [t.Color.ACCENT_ROSE, t.Color.ACCENT_PEACH, t.Color.ACCENT_CYAN]
        lbl = fonts.render(t.Type.META_SM, "getting things ready", t.Color.TEXT_MUTED)
        dot_gap = 12
        dots_w = dot_gap * (len(cols) - 1) + 6
        x = cx - (dots_w + 12 + lbl.get_width()) // 2
        for i, col in enumerate(cols):
            phase = self.elapsed / 1400.0 * 2 * math.pi - i * 1.1
            sc = 0.5 + 0.5 * math.sin(phase)
            a = int(90 + 165 * sc)
            r = 2 + int(2 * sc)
            dot = pygame.Surface((8, 8), pygame.SRCALPHA)
            pygame.draw.circle(dot, (*col, a), (4, 4), r)
            surf.blit(dot, (x + i * dot_gap - 4, y - 4))
        surf.blit(lbl, (x + dots_w + 12, y - lbl.get_height() // 2))


def _build_halo() -> pygame.Surface:
    """Soft rose→cyan radial glow that fades to transparent."""
    R = 290
    s = pygame.Surface((R * 2, R * 2), pygame.SRCALPHA)
    steps = 60
    for i in range(steps, 0, -1):
        frac = i / steps
        col = render._lerp(t.Color.ACCENT_CYAN, t.Color.ACCENT_ROSE, 1 - frac)
        a = int(30 * (1 - frac) ** 1.4)
        if a:
            pygame.draw.circle(s, (*col, a), (R, R), int(R * frac))
    return s
