"""
N1 — Notifications drawer.

A quiet right-side drawer over the dimmed home, built from REAL state
(`gui.library.notify`): library growth since you last looked, games in
progress, the Clerk's pick. A opens the linked target, B closes, L clears.

Opening the drawer = acknowledging it: we snapshot the feed first, THEN
mark the current library seen, so the welcome / "N joined your shelf"
item shows this once and the bell's unread dot clears on close.
"""

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, images
from ..library import notify

DRAWER_W = 388
DX = t.VIEWPORT_WIDTH - DRAWER_W
BODY_BOT = t.VIEWPORT_HEIGHT - t.Space.FOOTER_HINT_HEIGHT

VAR = {"clerk": ("ph-star", t.Color.ACCENT_PEACH),
       "dl": ("ph-check", t.Color.SUCCESS),
       "save": ("ph-floppy-disk", t.Color.ACCENT_CYAN),
       "upd": ("ph-download-simple", t.Color.ACCENT_ROSE)}


class NotificationsScreen:
    name = "notifications"

    def __init__(self, app):
        self.app = app
        ps = app.library.play_state()
        # Snapshot the feed BEFORE marking seen (so the welcome / growth
        # item reflects the pre-open state), then baseline the current
        # library as seen so the bell dot clears.
        self.items = notify.build_feed(app.catalog, ps)
        ps.mark_games_seen(notify.new_game_ids(app.catalog, ps))
        self.sel = 0

    def on_action(self, action):
        if action == "up":
            self.sel = max(0, self.sel - 1)
        elif action == "down":
            self.sel = min(max(0, len(self.items) - 1), self.sel + 1)
        elif action == "a" and self.items:
            self._open(self.items[self.sel]["act"])
        elif action == "l":
            # Real clear: drop the feed to the evergreen baseline. Growth /
            # welcome are already acknowledged (marked seen in __init__), so
            # rebuilding yields just the ambient items — an honest "cleared".
            self.items = [it for it in self.items if not it.get("unread")]
            self.sel = min(self.sel, max(0, len(self.items) - 1))
            self.app.toast("Caught up")
        elif action == "b":
            self.app.pop()                 # close drawer → back to where it opened

    def _open(self, act):
        if not act:
            return
        kind, arg = act
        if kind == "discover":
            self.app.go_tab("discover")
        elif kind == "library":
            self.app.go_tab("library")
        elif kind == "game":
            self.app.open_game(arg)

    def update(self, dt_ms):
        pass

    def draw(self, surf):
        cat = self.app.catalog
        # dimmed home behind
        ce = cat.continue_entries()
        bg_game = ce[0]["game"] if ce else cat.games[0]
        surf.blit(images.backdrop(cat.asset_path(bg_game, "hero"),
                                  t.VIEWPORT_WIDTH, t.VIEWPORT_HEIGHT, blur=16, darken=0.7),
                  (0, 0))
        veil = pygame.Surface((t.VIEWPORT_WIDTH, t.VIEWPORT_HEIGHT), pygame.SRCALPHA)
        veil.fill(t.with_alpha(t.Color.BG_DEEP, 0.5))
        surf.blit(veil, (0, 0))
        surf.blit(fonts.render(t.Type.EYEBROW, "AAHEAD", t.Color.TEXT_DISABLED), (16, 14))

        # drawer
        draw = pygame.Surface((DRAWER_W, BODY_BOT), pygame.SRCALPHA)
        draw.fill(t.with_alpha(t.Color.BG_MID, 0.92))
        pygame.draw.line(draw, t.with_alpha(t.Color.TEXT_PRIMARY, 0.06), (0, 0), (0, BODY_BOT), 1)
        surf.blit(draw, (DX, 0))

        # head
        surf.blit(fonts.render(t.Type.ROW_TITLE, "Notifications", t.Color.TEXT_PRIMARY),
                  (DX + 18, 14))
        clr = fonts.render(t.Type.MONO, "L  clear all", t.Color.TEXT_MUTED)
        surf.blit(clr, (t.VIEWPORT_WIDTH - 14 - clr.get_width(), 16))
        pygame.draw.line(surf, t.with_alpha(t.Color.TEXT_PRIMARY, 0.05),
                         (DX + 14, 42), (t.VIEWPORT_WIDTH - 14, 42), 1)

        # list (or a calm "all caught up" when empty)
        clip = pygame.Rect(DX, 48, DRAWER_W, BODY_BOT - 48)
        surf.set_clip(clip)
        if self.items:
            y = 56
            for i, it in enumerate(self.items):
                y = self._notif(surf, y, it, focused=(i == self.sel)) + 8
        else:
            ic = icons.icon("ph-check-circle", 22, t.Color.TEXT_MUTED)
            surf.blit(ic, (DX + 18, 64))
            surf.blit(fonts.render(t.Type.BODY, "You're all caught up.",
                                   t.Color.TEXT_SECONDARY), (DX + 18, 96))
        surf.set_clip(None)

        hints = [("A", "Open"), ("B", "Close")]
        if any(it.get("unread") for it in self.items):
            hints.append(("L1", "Clear"))
        chrome.footer_hints(surf, hints)

    def _notif(self, surf, y, it, *, focused):
        x = DX + 14
        w = DRAWER_W - 28
        icon_name, col = VAR[it["var"]]
        # measure detail to size the card
        det_lines = c.wrap_text(t.Type.CAPTION, it["det"], w - 28 - 12)[:2]
        h = 10 + 16 + 2 + len(det_lines) * 16 + 10
        r = pygame.Rect(x, y, w, h)
        body = pygame.Surface((w, h), pygame.SRCALPHA)
        pygame.draw.rect(body, t.with_alpha(t.Color.SURFACE_BASE, 0.6), (0, 0, w, h),
                         border_radius=9)
        if not focused:
            pygame.draw.rect(body, t.Color.BORDER_SOFT, (0, 0, w, h), width=1, border_radius=9)
        # icon chip
        ib = pygame.Rect(12, 10, 28, 28)
        pygame.draw.rect(body, t.with_alpha(col, 0.10), ib, border_radius=7)
        pygame.draw.rect(body, t.with_alpha(col, 0.28), ib, width=1, border_radius=7)
        ic = icons.icon(icon_name, 14, col)
        body.blit(ic, (ib.centerx - 7, ib.centery - 7))
        tx = 12 + 28 + 11
        # title (+ an unread dot in place of the old mock timestamp)
        nm = fonts.render(t.Type.LABEL, c._ellipsize(t.Type.LABEL, it["title"], w - tx - 28),
                          t.Color.TEXT_PRIMARY)
        body.blit(nm, (tx, 11))
        if it.get("unread"):
            pygame.draw.circle(body, t.Color.ACCENT_ROSE, (w - 16, 18), 3)
        # detail
        for k, ln in enumerate(det_lines):
            body.blit(fonts.render(t.Type.CAPTION, ln, t.Color.TEXT_SECONDARY),
                      (tx, 30 + k * 16))
        if focused:
            glow, gpos = render.focus_glow(r, 9); surf.blit(glow, gpos)
        surf.blit(body, r.topleft)
        if focused:
            surf.blit(render.gradient_border((w, h), 9), r.topleft)
        return r.bottom
