"""
wivexx_status_overlay.py — top-left activity badge overlay  (v1.0)
═══════════════════════════════════════════════════════════════════════
A small translucent pill that appears in the TOP-LEFT of the screen while one of
Wivexx's input-automation features is live, so you always know it's running:

  "clicker"   → AUTOCLICKER badge (volt mouse, button blinks on the click beat)
  "recording" → REC badge (blinking red dot + elapsed / actions)
  "playback"  → PLAYING badge (volt ▶ + loop count)
  ""          → hidden

It is driven by the SAME unified signal as the mascot pose (set_gadget → set_kind),
so it never needs its own detection. Same per-pixel-alpha technique as
wivexx_perf_osd: a Tk top-level whose pixels are pushed via UpdateLayeredWindow
(reusing wivexx_ball_overlay._Layered), and it's CLICK-THROUGH (WS_EX_TRANSPARENT)
+ topmost + no-activate + tool-window, so it floats over fullscreen games and
NEVER steals the clicks/keystrokes the auto-clicker or playback is sending.

Public API (driven from wivexx_gui, on the tk sidecar root):
    ov = StatusOverlay(root)
    ov.set_kind("clicker" | "recording" | "playback" | "")
"""

from typing import Optional

from PIL import Image, ImageDraw, ImageFont

_INK = (13, 13, 13)
_VOLT = (193, 247, 58)
_BONE = (242, 240, 234)
_STONE = (150, 150, 144)
_GRAPHITE = (40, 40, 37)
_RED = (226, 59, 59)

_W = 250                 # pill width (px)
_H = 48                  # pill height (px)
_SS = 2                  # supersample for crisp text/edges
_MARGIN = 18             # gap from the top-left screen corner

_LABEL = {"recording": "REC", "playback": "PLAYING", "clicker": "AUTOCLICKER"}
_KINDS = ("recording", "playback", "clicker")


def _font(sz, bold=False):
    for p in (("C:/Windows/Fonts/consolab.ttf",) if bold else ("C:/Windows/Fonts/consola.ttf",)):
        try:
            return ImageFont.truetype(p, sz)
        except Exception:
            pass
    return ImageFont.load_default()


def render(kind: str, detail: str, blink: bool, opacity: float) -> Image.Image:
    """Build the translucent badge as an RGBA image (per-pixel alpha)."""
    W, H, ss = _W, _H, _SS
    pa = max(0.3, min(1.0, float(opacity)))
    bg_a = int(220 * pa)
    accent = _RED if kind == "recording" else _VOLT
    img = Image.new("RGBA", (W * ss, H * ss), (0, 0, 0, 0))
    dr = ImageDraw.Draw(img)

    # rounded translucent pill + a faint accent hairline
    rad = 13 * ss
    dr.rounded_rectangle([ss, ss, (W - 1) * ss, (H - 1) * ss], radius=rad,
                         fill=_INK + (bg_a,), outline=accent + (int(135 * pa),),
                         width=max(1, ss))
    # a solid accent bar down the left edge (the "live" tab)
    dr.rounded_rectangle([3 * ss, 8 * ss, 6 * ss, (H - 8) * ss], radius=2 * ss,
                         fill=accent + (int(235 * pa),))

    ix, iy = 24 * ss, (H // 2) * ss
    if kind == "recording":                      # blinking red tally dot
        r = 7 * ss
        a = 255 if blink else 80
        dr.ellipse([ix - r, iy - r, ix + r, iy + r], fill=_RED + (a,))
    elif kind == "playback":                     # volt play triangle
        r = 8 * ss
        dr.polygon([(ix - r * 0.7, iy - r), (ix - r * 0.7, iy + r), (ix + r * 0.95, iy)],
                   fill=_VOLT + (255,))
    else:                                        # clicker — a little mouse, button blinks
        mw, mh = 12 * ss, 16 * ss
        dr.rounded_rectangle([ix - mw / 2, iy - mh / 2, ix + mw / 2, iy + mh / 2],
                             radius=mw * 0.45, fill=_GRAPHITE + (255,),
                             outline=_VOLT + (255,), width=max(1, ss))
        dr.line([(ix, iy - mh / 2), (ix, iy)], fill=_VOLT + (170,), width=max(1, ss))
        if blink:
            dr.rounded_rectangle([ix - mw / 2 + 1.4 * ss, iy - mh / 2 + 1.4 * ss,
                                  ix - 1.2 * ss, iy - 1.2 * ss],
                                 radius=mw * 0.2, fill=_VOLT + (225,))

    # label (bold) + live detail (small, stone)
    tx = 44 * ss
    dr.text((tx, 7 * ss), _LABEL.get(kind, ""), font=_font(13 * ss, True), fill=_BONE + (255,))
    if detail:
        dr.text((tx, 27 * ss), detail, font=_font(10 * ss), fill=_STONE + (255,))

    if ss != 1:
        img = img.resize((W, H), Image.BILINEAR)
    return img


class StatusOverlay:
    """A transparent, click-through, topmost activity badge on the tk sidecar root."""

    def __init__(self, root, opacity: float = 0.9) -> None:
        self._root = root
        self._opacity = opacity
        self._win = None
        self._layered = None
        self._kind = ""
        self._shown = False
        self._running = False
        self._blink = True

    # ── construction ───────────────────────────────────────────────────────────
    def _build(self):
        import tkinter as tk
        win = tk.Toplevel(self._root)
        self._win = win
        win.withdraw()
        win.overrideredirect(True)
        win.attributes("-topmost", True)
        try:
            win.wm_attributes("-toolwindow", True)
        except Exception:
            pass
        win.geometry(f"{_W}x{_H}+{_MARGIN}+{_MARGIN}")
        win.update_idletasks()
        try:
            from wivexx_ball_overlay import _Layered
            self._layered = _Layered(win.winfo_id(), (_W, _H))
        except Exception:
            self._layered = None
        self._apply_styles()

    def _apply_styles(self):
        """Click-through (WS_EX_TRANSPARENT) + no-activate + tool-window + topmost,
        so the badge never intercepts the very clicks/keys the feature is sending.
        WS_EX_LAYERED is already set by _Layered for the per-pixel alpha."""
        try:
            import ctypes
            from ctypes import wintypes
            u = ctypes.windll.user32
            try:
                getL, setL, LT = u.GetWindowLongPtrW, u.SetWindowLongPtrW, ctypes.c_ssize_t
            except AttributeError:
                getL, setL, LT = u.GetWindowLongW, u.SetWindowLongW, ctypes.c_long
            getL.restype = LT
            getL.argtypes = [wintypes.HWND, ctypes.c_int]
            setL.restype = LT
            setL.argtypes = [wintypes.HWND, ctypes.c_int, LT]
            GA_ROOT = 2
            hwnd = u.GetAncestor(self._win.winfo_id(), GA_ROOT) or self._win.winfo_id()
            GWL_EXSTYLE = -20
            WS_EX_TRANSPARENT = 0x20
            WS_EX_TOOLWINDOW = 0x80
            WS_EX_NOACTIVATE = 0x08000000
            WS_EX_TOPMOST = 0x8
            cur = getL(hwnd, GWL_EXSTYLE)
            setL(hwnd, GWL_EXSTYLE,
                 cur | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TOPMOST)
        except Exception:
            pass

    # ── live detail line per kind ────────────────────────────────────────────────
    def _detail(self) -> str:
        kind = self._kind
        try:
            if kind in ("recording", "playback"):
                import wivexx_macro as mac
                s = mac.status()
                if kind == "recording":
                    return f"{int(s.get('elapsed', 0))}s  ·  {s.get('events', 0)} actions"
                loops = s.get("loops_done", 0)
                tot = s.get("total_loops", 0)
                return f"loop {loops}/{tot}" if tot else f"loop {loops}"
            if kind == "clicker":
                import wivexx_autoclicker as ac
                su = ac.active_summary()
                cps = su.get("cps", 0)
                cnt = su.get("count", 1)
                base = f"{cps} cps" if cps else "on"
                return base + (f"  ·  {cnt} keys" if cnt > 1 else "")
        except Exception:
            pass
        return ""

    def _draw(self):
        if not self._layered or not self._kind:
            return
        try:
            img = render(self._kind, self._detail(), self._blink, self._opacity)
            self._layered.present(img)
        except Exception:
            pass

    def _tick(self):
        if not self._shown:
            self._running = False
            return
        self._blink = not self._blink
        self._draw()
        try:
            self._win.attributes("-topmost", True)
        except Exception:
            pass
        try:
            self._root.after(280, self._tick)
        except Exception:
            self._running = False

    # ── public ────────────────────────────────────────────────────────────────
    def set_kind(self, kind: str) -> None:
        """Show the badge for kind ("clicker"|"recording"|"playback") or hide ("")."""
        kind = kind if kind in _KINDS else ""
        if kind == self._kind and (self._shown == bool(kind)):
            if kind:
                self._draw()          # same kind → just refresh the detail
            return
        self._kind = kind
        if not kind:
            self._hide()
            return
        self._show()

    def _show(self):
        if self._win is None:
            self._build()
        self._blink = True
        try:
            self._win.geometry(f"{_W}x{_H}+{_MARGIN}+{_MARGIN}")
            self._win.deiconify()
            self._win.lift()
            self._win.attributes("-topmost", True)
        except Exception:
            pass
        self._shown = True
        self._draw()
        if not self._running:
            self._running = True
            self._tick()

    def _hide(self):
        self._shown = False
        try:
            if self._win is not None:
                self._win.withdraw()
        except Exception:
            pass

    def is_shown(self) -> bool:
        return self._shown


if __name__ == "__main__":
    # offline render preview (no tk window) — composite the 3 badges over a fake desktop
    rows = [("recording", "12s  ·  340 actions", True),
            ("playback", "loop 3/10", True),
            ("clicker", "25 cps", True)]
    pad = 12
    sheet = Image.new("RGBA", (_W + pad * 2, (_H + pad) * len(rows) + pad), (44, 48, 56, 255))
    for i, (k, d, b) in enumerate(rows):
        badge = render(k, d, b, 0.9)
        sheet.alpha_composite(badge, (pad, pad + i * (_H + pad)))
    sheet.convert("RGB").save("_status_overlay_preview.png")
    print("wrote _status_overlay_preview.png", (_W, _H))
