"""
A1 — Add games. A store-style UI layer over an EXTERNAL source (we host nothing).

Featured "add-it-now" pick as a split-hero (peach, with a source attribution
pill), then a store browse: filter chips (All / systems / tags) + a sort/count
line + an edge-to-edge poster strip. Already-on-device picks carry a green check.
Reached from Discover / Search. X toggles the offline (source-unavailable) state.
"""

from __future__ import annotations

import pygame

from ..design import tokens as t
from ..shared import fonts, render, icons
from ..widgets import chrome, components as c, nav, hero as herow

BODY_TOP = t.Space.STATUS_BAR_HEIGHT
BODY_BOT = t.VIEWPORT_HEIGHT - t.Space.FOOTER_HINT_HEIGHT

HERO = pygame.Rect(0, BODY_TOP, t.VIEWPORT_WIDTH, 200)     # 28..228
FILTER_Y = 240
HEAD_Y = 262
STRIP_Y = 284
TILE_W, TILE_AH, TILE_GAP = 104, 130, 1   # art sized so name+sub clear the footer

# Approximate ROM sizes per system (the source is mocked; sizes are illustrative).
SIZES = {"NES": "256 KB", "Famicom": "256 KB", "SNES": "2 MB", "Genesis": "2 MB",
         "N64": "16 MB", "GBA": "8 MB", "Game Boy": "512 KB", "Game Boy Color": "1 MB",
         "Master System": "256 KB", "Game Gear": "512 KB", "PS1": "500 MB",
         "PSP": "900 MB", "PC Engine": "256 KB", "Neo Geo": "40 MB"}


class AddGamesScreen:
    name = "add_games"

    def __init__(self, app, online=True):
        self.app = app
        self.nav = nav.NavBar("discover")
        self.online = online
        cat = app.catalog
        self.pool = sorted(cat.games, key=lambda g: (g.get("rating") or 0), reverse=True)
        self.featured = self.pool[0] if self.pool else None
        self.have = ({e["game"]["id"] for e in cat.continue_entries()}
                     | {g["id"] for g in cat.favorites()})
        self.chips = ([("All", None)]
                      + [(s, ("sys", s)) for s in cat.systems]
                      + [("Hidden gems", ("tag", "gems")),
                         ("Homebrew", ("tag", "homebrew")),
                         ("Translations", ("tag", "trans"))])
        self.active = 0          # applied filter index
        self.cidx = 0            # chip cursor
        self.area = "hero"       # 'hero' | 'chips' | 'strip'
        self.sel = 0
        self.start = 0
        self._apply()

    def _apply(self):
        f = self.chips[self.active][1]
        base = [g for g in self.pool if g is not self.featured]
        if f is None:
            items = base
        elif f[0] == "sys":
            items = [g for g in base if g["system"] == f[1]]
        elif f[1] == "gems":
            items = [g for g in base if 3.5 <= (g.get("rating") or 0) < 4.5]
        else:                    # homebrew / translations — none in the mock set
            items = []
        self.items = items
        self.sel = 0
        self.start = 0

    def _size(self, g):
        return SIZES.get(g["system"], "—")

    # ── input ────────────────────────────────────────────────────────
    def on_action(self, action):
        if self.nav.handle(self.app, action):
            return
        if action == "x":
            self.online = not self.online
            return
        if not self.online:
            if action == "up":
                self.nav.focus()
            elif action == "a":
                self.online = True
            elif action == "b":
                self.app.pop()
            return
        if action == "b":
            self.app.pop()
        elif action == "y":
            self.app.go_tab("search")
        elif action in ("azprev", "aznext"):       # right stick → fast scroll the strip
            if self.items:
                self.area = "strip"
                step = 5 if action == "aznext" else -5
                self.sel = max(0, min(len(self.items) - 1, self.sel + step))
        elif self.area == "hero":
            self._hero_input(action)
        elif self.area == "chips":
            self._chips_input(action)
        else:
            self._strip_input(action)

    def _hero_input(self, action):
        if action == "up":
            self.nav.focus()
        elif action == "down":
            self.area = "chips"
        elif action == "a" and self.featured:
            self.app.toast(f"Queued {self.featured['title']} · {self._size(self.featured)}")

    def _chips_input(self, action):
        if action == "up":
            self.area = "hero"
        elif action == "down" and self.items:        # don't descend into an empty strip
            self.area = "strip"; self.sel = 0
        elif action == "left":
            self.cidx = max(0, self.cidx - 1)
        elif action == "right":
            self.cidx = min(len(self.chips) - 1, self.cidx + 1)
        elif action == "a":
            self.active = self.cidx
            self._apply()

    def _strip_input(self, action):
        if not self.items:                            # empty filter → bounce to chips
            self.area = "chips"; return
        if action == "up":
            self.area = "chips"
        elif action == "left":
            self.sel = max(0, self.sel - 1)
        elif action == "right":
            self.sel = min(len(self.items) - 1, self.sel + 1)
        elif action == "a" and self.items:
            g = self.items[self.sel]
            if g["id"] in self.have:
                self.app.toast(f"{g['title']} is already on this device")
            else:
                self.app.open_game(g["id"], installed=False)

    def update(self, dt_ms):
        pass

    # ── draw ─────────────────────────────────────────────────────────
    def draw(self, surf):
        self.nav.draw(surf, app=self.app)
        navf = self.nav.focused
        if not self.online:
            self._offline(surf)
            chrome.footer_hints(surf, [("A", "Retry"), ("B", "Back")])
            return
        self._draw_hero(surf, self.area == "hero" and not navf)
        self._draw_chips(surf, self.area == "chips" and not navf)
        self._draw_head(surf)
        self._draw_strip(surf, self.area == "strip" and not navf)
        a_lbl = "Filter" if self.area == "chips" else "Add"
        chrome.footer_hints(surf, [("A", a_lbl), ("B", "Back"), ("Y", "Search source")])

    def _draw_hero(self, surf, focused):
        if not self.featured:
            return
        g = self.featured
        cat = self.app.catalog
        herow.split_hero(surf, HERO, art_path=cat.asset_path(g, "hero"),
                         eyebrow="The Clerk's add-it-now", eyebrow_color=t.Color.ACCENT_PEACH,
                         title=g["title"], title_style=t.Type.DISPLAY,
                         meta=[g["system"], g.get("year"), (g.get("genre") or [None])[0]],
                         quote=None, cta_label=f"Add to library · {self._size(g)}",
                         cta_focused=focused, art_focus=(0.5, 0.35))
        self._source_pill(surf)

    def _source_pill(self, surf):
        lab = fonts.render(t.Type.TILE_SUB, "via myrient·erista", t.Color.TEXT_SECONDARY)
        bd = 16
        pad = 8
        w = bd + 6 + lab.get_width() + pad
        h = 20
        x = t.VIEWPORT_WIDTH - 14 - w
        y = HERO.y + 14
        chip = pygame.Surface((w, h), pygame.SRCALPHA)
        pygame.draw.rect(chip, t.with_alpha(t.Color.BG_DEEP, 0.6), (0, 0, w, h),
                         border_radius=t.Radius.PILL)
        pygame.draw.rect(chip, t.with_alpha(t.Color.ACCENT_CYAN, 0.30), (0, 0, w, h),
                         width=1, border_radius=t.Radius.PILL)
        pygame.draw.circle(chip, t.with_alpha(t.Color.ACCENT_CYAN, 0.18), (2 + bd // 2, h // 2),
                           bd // 2)
        a = fonts.render(t.Type.GP, "A", t.Color.ACCENT_CYAN)
        chip.blit(a, (2 + bd // 2 - a.get_width() // 2, h // 2 - a.get_height() // 2))
        chip.blit(lab, (2 + bd + 6, (h - lab.get_height()) // 2))
        surf.blit(chip, (x, y))

    def _draw_chips(self, surf, active):
        # measure + position every chip, then scroll so the cursor chip is
        # always fully on-screen (focus can no longer hide off the right edge)
        gap = 5
        widths = [fonts.measure(t.Type.BTN, lbl)[0] + 18 for lbl, _ in self.chips]
        xs, acc = [], 14
        for w in widths:
            xs.append(acc); acc += w + gap
        off = 0
        if active:
            cx, cw = xs[self.cidx], widths[self.cidx]
            right = t.VIEWPORT_WIDTH - 14
            if cx < 14:
                off = cx - 14
            if cx + cw - off > right:
                off = cx + cw - right
        prev = surf.get_clip()
        surf.set_clip(pygame.Rect(0, FILTER_Y - 2, t.VIEWPORT_WIDTH, 26))
        for i, (label, f) in enumerate(self.chips):
            x = xs[i] - off
            cw = widths[i]
            if x + cw < 0 or x > t.VIEWPORT_WIDTH:
                continue
            is_active = (i == self.active)
            is_cur = (active and i == self.cidx)
            if f and f[0] == "tag":
                col = t.Color.ACCENT_PEACH
            elif f and f[0] == "sys":
                col = t.Color.TEXT_SECONDARY
            else:
                col = t.Color.TEXT_MUTED
            if is_active or is_cur:
                col = t.Color.TEXT_PRIMARY
            if is_active:
                pygame.draw.rect(surf, t.Color.SURFACE_BASE, (x, FILTER_Y, cw, 20),
                                 border_radius=t.Radius.PILL)
            if is_cur:
                pygame.draw.rect(surf, t.with_alpha(t.Color.TEXT_PRIMARY, 0.25),
                                 (x, FILTER_Y, cw, 20), width=1, border_radius=t.Radius.PILL)
            surf.blit(fonts.render(t.Type.BTN, label, col),
                      (x + 9, FILTER_Y + (20 - fonts.measure(t.Type.BTN, label)[1]) // 2))
            if is_active:
                surf.blit(render.linear_gradient((cw - 18, 2), t.Color.ACCENT_ROSE,
                                                 t.Color.ACCENT_CYAN, 90.0),
                          (x + 9, FILTER_Y + 20))
        # right-edge fade so a chip clipped at the edge fades out cleanly
        fw = 28
        fade = pygame.Surface((fw, 24), pygame.SRCALPHA)
        for fx in range(fw):
            fade.fill(t.with_alpha(t.Color.BG_DEEP, fx / (fw - 1)), (fx, 0, 1, 24))
        surf.blit(fade, (t.VIEWPORT_WIDTH - fw, FILTER_Y - 2))
        surf.set_clip(prev)

    def _draw_head(self, surf):
        ts = fonts.render(t.Type.SECTION, "All picks from the source", t.Color.TEXT_PRIMARY)
        surf.blit(ts, (14, HEAD_Y))
        cnt = fonts.render(t.Type.TILE_SUB, f"sort · recent     {len(self.items)} games",
                           t.Color.TEXT_MUTED)
        surf.blit(cnt, (t.VIEWPORT_WIDTH - 14 - cnt.get_width(), HEAD_Y + 2))

    def _draw_strip(self, surf, active):
        if not self.items:
            ns = fonts.render(t.Type.BODY, "Nothing tagged that from the source yet.",
                              t.Color.TEXT_MUTED)
            surf.blit(ns, (14, STRIP_Y + 20))
            return
        n = len(self.items)
        view = (t.VIEWPORT_WIDTH - 14) // (TILE_W + TILE_GAP)
        self.start = max(0, min(self.sel - view + 2, max(0, n - view))) if active else 0
        for k in range(self.start, min(self.start + view + 1, n)):
            g = self.items[k]
            x = 14 + (k - self.start) * (TILE_W + TILE_GAP)
            self._tile(surf, x, g, focused=(active and k == self.sel),
                       dim=(active and k != self.sel))

    def _tile(self, surf, x, g, *, focused, dim):
        ar = pygame.Rect(x, STRIP_Y, TILE_W, TILE_AH)
        have = g["id"] in self.have
        sub = "already on device" if have else self._size(g)
        c.poster_tile(surf, ar, path=self.app.catalog.asset_path(g, "box"),
                      name=g["title"], badge=c.rating_badge(g.get("rating")),
                      badge_r=(None if have else g["system"]), sub=sub,
                      focused=focused, dim=dim)
        if have:
            self._check(surf, ar.right - 24, ar.y + 6)

    def _check(self, surf, x, y):
        d = 22
        chip = pygame.Surface((d, d), pygame.SRCALPHA)
        pygame.draw.circle(chip, t.with_alpha(t.Color.SUCCESS, 0.20), (d // 2, d // 2), d // 2)
        pygame.draw.circle(chip, t.with_alpha(t.Color.SUCCESS, 0.45), (d // 2, d // 2),
                           d // 2, width=1)
        ic = icons.icon("ph-check", 11, t.Color.SUCCESS)
        chip.blit(ic, ((d - 11) // 2, (d - 11) // 2))
        surf.blit(chip, (x, y))

    def _offline(self, surf):
        cx, cy = t.VIEWPORT_WIDTH // 2, 250
        ic = icons.icon("ph-wifi-slash", 48, t.Color.TEXT_MUTED)
        surf.blit(ic, (cx - 24, cy - 60))
        msg = fonts.render(t.Type.TITLE, "Source unavailable", t.Color.TEXT_SECONDARY)
        surf.blit(msg, (cx - msg.get_width() // 2, cy))
        sub = fonts.render(t.Type.BODY, "Check your Wi-Fi and try again.", t.Color.TEXT_MUTED)
        surf.blit(sub, (cx - sub.get_width() // 2, cy + 28))
