"""Narration panel for the KiCad tour.

Styled to match the Adom Desktop Tauri app exactly:
  Colors: desktop/src/style.css CSS custom properties
  Fonts:  Segoe UI (body) + Cascadia Code (mono)
  Layout: bg-primary page, bg-secondary panels, bg-tertiary hover

Runs standalone with an HTTP server so Claude can push updates:
    python narration.py [--port 8799]

HTTP API:
    POST /update   {"step":1,"total":19,"title":"...","description":"...",
                     "act":"...","status":"...","status_color":"#3fb950",
                     "data":"...","data_color":"#3fb950"}
    POST /quit     Close the panel
    GET  /health   {"status":"ok"}
"""

import argparse
import ctypes
import json
import sys
import threading
import tkinter as tk
from http.server import HTTPServer, BaseHTTPRequestHandler
from tkinter import ttk


# ── Colors — exact match to desktop/src/style.css :root vars ─────
BG_PRIMARY = "#0d1117"       # --bg-primary  (page background)
BG_SECONDARY = "#161b22"     # --bg-secondary (panels, toolbars)
BG_TERTIARY = "#21262d"      # --bg-tertiary  (hover, elevated)
BORDER = "#30363d"           # --border
TEXT_PRIMARY = "#e6edf3"     # --text-primary
TEXT_SECONDARY = "#8b949e"   # --text-secondary
TEXT_MUTED = "#6e7681"       # --text-muted
ACCENT = "#58a6ff"           # --accent
GREEN = "#3fb950"            # --green
RED = "#f85149"              # --red
YELLOW = "#d29922"           # --yellow
ORANGE = "#db6d28"           # --orange

# Brand accent
TEAL = "#00b8b1"
TEAL_BRIGHT = "#00e6dc"
PURPLE = "#8C6BF7"
PURPLE_LIGHT = "#C5B3FF"
BLUE = ACCENT
BLUE_LIGHT = "#64ABFF"

# Backward-compat aliases
FG = TEXT_PRIMARY
FG_DIM = TEXT_MUTED
FG_SECONDARY = TEXT_SECONDARY

# ── Typography ──────────────────────────────────────────────────
FONT_TITLE = ("Segoe UI", 18, "bold")
FONT_H2 = ("Segoe UI", 15, "bold")
FONT_ACT = ("Segoe UI", 11, "bold")
FONT_DESC = ("Segoe UI", 13)
FONT_MONO = ("Cascadia Code", 12)
FONT_STATUS = ("Segoe UI", 13)
FONT_BTN = ("Segoe UI", 13)
FONT_SMALL = ("Segoe UI", 12)
FONT_TAG = ("Segoe UI", 11, "bold")


class NarrationPanel:
    """Always-on-top narration panel — styled identical to Adom Desktop."""

    def __init__(self, width: int = 480, on_quit=None):
        self.width = width
        self._on_quit = on_quit

        self.root = tk.Tk()
        self.root.title("Gallia Tour")
        self.root.configure(bg=BG_PRIMARY)
        self.root.attributes("-topmost", True)

        # Position on the right side of the screen, accounting for taskbar.
        # Use tkinter's own screen dimensions (logical pixels) so geometry
        # values are consistent regardless of DPI awareness.
        screen_w = self.root.winfo_screenwidth()
        screen_h = self.root.winfo_screenheight()
        # Subtract space for the taskbar (~50 logical px) and titlebar (~32 px)
        # to guarantee the Quit button is fully visible.
        panel_h = screen_h - 80
        x = screen_w - width
        self.root.geometry(f"{width}x{panel_h}+{x}+0")
        self.root.resizable(False, False)

        self.root.protocol("WM_DELETE_WINDOW", self._quit)

        self._build_ui()

        # Apply dark mode to the native Windows titlebar via DWM API.
        # This gives us a dark titlebar that matches the app without
        # removing it (which caused the invisible-window bug).
        self.root.update_idletasks()
        self._apply_dark_titlebar()

    def _apply_dark_titlebar(self):
        """Use DWM API to render the native titlebar in dark mode (Win10 1809+)."""
        try:
            hwnd = ctypes.windll.user32.GetParent(self.root.winfo_id())
            # DWMWA_USE_IMMERSIVE_DARK_MODE = 20 (Windows 10 1809+)
            DWMWA_USE_IMMERSIVE_DARK_MODE = 20
            value = ctypes.c_int(1)  # TRUE = dark mode
            ctypes.windll.dwmapi.DwmSetWindowAttribute(
                hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE,
                ctypes.byref(value), ctypes.sizeof(value),
            )
        except Exception:
            pass  # Fall back to default titlebar if DWM not available

    def _build_ui(self):
        # ── Status bar (matches #top-bar status group) ───
        status_bar = tk.Frame(self.root, bg=BG_SECONDARY, padx=16, pady=8)
        status_bar.pack(fill="x")

        # Green dot + step counter (like the Connected indicator)
        dot_canvas = tk.Canvas(
            status_bar, width=14, height=14,
            bg=BG_SECONDARY, highlightthickness=0,
        )
        dot_canvas.pack(side="left", padx=(0, 8))
        self._dot = dot_canvas
        self._dot_id = dot_canvas.create_oval(2, 2, 12, 12, fill=GREEN, outline="")

        self._step_label = tk.Label(
            status_bar, text="Gallia Feature Tour", font=FONT_SMALL,
            bg=BG_SECONDARY, fg=TEXT_SECONDARY,
        )
        self._step_label.pack(side="left")

        self._act_tag = tk.Label(
            status_bar, text="", font=FONT_TAG,
            bg="#1a1a33", fg="#a78bfa",
            padx=6, pady=1,
        )
        self._act_tag.pack(side="right")

        # Border
        tk.Frame(self.root, bg=BORDER, height=1).pack(fill="x")

        # ── Progress bar ─────────────────────────────
        prog_frame = tk.Frame(self.root, bg=BG_PRIMARY, padx=16)
        prog_frame.pack(fill="x", pady=(8, 0))

        style = ttk.Style()
        style.theme_use("default")
        style.configure(
            "Tour.Horizontal.TProgressbar",
            troughcolor=BG_TERTIARY,
            background=TEAL,
            thickness=4,
        )
        self._progress = ttk.Progressbar(
            prog_frame, style="Tour.Horizontal.TProgressbar",
            length=self.width - 32, mode="determinate",
        )
        self._progress.pack(fill="x")

        # ── Content area ─────────────────────────────
        content_frame = tk.Frame(self.root, bg=BG_PRIMARY, padx=16, pady=12)
        content_frame.pack(fill="x")

        self._section_label = tk.Label(
            content_frame, text="FEATURE TOUR", font=FONT_H2,
            bg=BG_PRIMARY, fg=TEXT_SECONDARY,
        )
        self._section_label.pack(anchor="w")

        self._title_label = tk.Label(
            content_frame, text="Waiting for Claude...", font=FONT_TITLE,
            bg=BG_PRIMARY, fg=TEXT_PRIMARY, anchor="w",
            wraplength=self.width - 32, justify="left",
        )
        self._title_label.pack(fill="x", pady=(8, 0))

        tk.Frame(self.root, bg=BORDER, height=1).pack(fill="x", padx=16, pady=8)

        self._desc_label = tk.Label(
            self.root, text="The tour will begin shortly.\nClaude is analyzing your setup...",
            font=FONT_DESC,
            bg=BG_PRIMARY, fg=TEXT_SECONDARY, padx=16, anchor="nw",
            wraplength=self.width - 32, justify="left",
        )
        self._desc_label.pack(fill="x")

        # ── Status line ──────────────────────────────
        self._status_label = tk.Label(
            self.root, text="", font=FONT_STATUS,
            bg=BG_PRIMARY, fg=GREEN, padx=16, anchor="w",
        )
        self._status_label.pack(fill="x", pady=(8, 0))

        # ── Data area (matches #activity-log) ────────
        data_outer = tk.Frame(self.root, bg=BG_PRIMARY, padx=16, pady=8)
        data_outer.pack(fill="both", expand=True)

        data_border = tk.Frame(data_outer, bg=BORDER, padx=1, pady=1)
        data_border.pack(fill="both", expand=True)

        self._data_text = tk.Text(
            data_border, font=FONT_MONO,
            bg=BG_SECONDARY, fg=TEXT_PRIMARY,
            insertbackground=GREEN,
            selectbackground=BG_TERTIARY,
            relief="flat", wrap="word",
            padx=8, pady=8,
            borderwidth=0, highlightthickness=0,
        )
        self._data_text.pack(fill="both", expand=True)
        self._data_text.config(state="disabled")

        # ── Button bar (matches #stats-footer) ───────
        tk.Frame(self.root, bg=BORDER, height=1).pack(fill="x", side="bottom")

        btn_frame = tk.Frame(self.root, bg=BG_SECONDARY, pady=8, padx=16)
        btn_frame.pack(fill="x", side="bottom")

        tk.Button(
            btn_frame, text="Quit Tour", command=self._quit,
            font=FONT_BTN, bg="#da3633", fg="#ffffff",
            activebackground="#b62324", activeforeground="#ffffff",
            relief="flat", padx=14, pady=6, cursor="hand2",
            borderwidth=1, highlightthickness=0,
        ).pack(side="right")

        # "Powered by Claude" label
        tk.Label(
            btn_frame, text="Powered by Claude",
            font=FONT_SMALL, bg=BG_SECONDARY, fg=TEXT_MUTED,
        ).pack(side="left")

    # ── Public API (thread-safe via root.after) ───────────────────

    def set_step(self, number: int, total: int, title: str, description: str,
                 act: str = ""):
        self._step_label.config(text=f"Step {number} of {total}")
        self._progress["maximum"] = total
        self._progress["value"] = number
        if act:
            self._act_tag.config(text=act.upper())
        self._title_label.config(text=title)
        self._desc_label.config(text=description)
        self._status_label.config(text="")
        self._data_text.config(state="normal")
        self._data_text.delete("1.0", "end")
        self._data_text.config(state="disabled")

    def set_status(self, text: str, color: str = GREEN):
        self._status_label.config(text=text, fg=color)

    def set_data(self, text: str):
        self._data_text.config(state="normal")
        self._data_text.delete("1.0", "end")
        self._data_text.insert("1.0", text)
        self._data_text.config(state="disabled")

    def set_data_color(self, color: str):
        self._data_text.config(fg=color)

    def apply_update(self, data: dict):
        """Apply a dict of updates from the HTTP API."""
        if "step" in data and "total" in data:
            self.set_step(
                data["step"], data["total"],
                data.get("title", ""), data.get("description", ""),
                data.get("act", ""),
            )
        else:
            if "title" in data:
                self._title_label.config(text=data["title"])
            if "description" in data:
                self._desc_label.config(text=data["description"])
            if "act" in data:
                self._act_tag.config(text=data["act"].upper())
        if "status" in data:
            color = data.get("status_color", GREEN)
            self.set_status(data["status"], color)
        if "data" in data:
            self.set_data(data["data"])
        if "data_color" in data:
            self.set_data_color(data["data_color"])

    # ── HTTP server for Claude to push updates ────────────────────

    def start_server(self, port: int = 8799):
        """Start the HTTP control server on a background thread."""
        panel = self

        class Handler(BaseHTTPRequestHandler):
            def do_POST(self):
                if self.path == "/update":
                    length = int(self.headers.get("Content-Length", 0))
                    body = json.loads(self.rfile.read(length)) if length else {}
                    panel.root.after(0, lambda: panel.apply_update(body))
                    self._respond(200, {"ok": True})
                elif self.path == "/quit":
                    self._respond(200, {"ok": True})
                    panel.root.after(100, panel.root.destroy)
                else:
                    self._respond(404, {"error": "not found"})

            def do_GET(self):
                if self.path == "/health":
                    self._respond(200, {"status": "ok", "port": port})
                else:
                    self._respond(404, {"error": "not found"})

            def _respond(self, code, data):
                self.send_response(code)
                self.send_header("Content-Type", "application/json")
                self.end_headers()
                self.wfile.write(json.dumps(data).encode())

            def log_message(self, fmt, *args):
                pass  # Suppress request logging

        server = HTTPServer(("127.0.0.1", port), Handler)
        t = threading.Thread(target=server.serve_forever, daemon=True)
        t.start()
        return server

    # ── Internal ──────────────────────────────────────────────────

    def _quit(self):
        if self._on_quit:
            self._on_quit()
        self.root.destroy()


# ── Standalone mode ──────────────────────────────────────────────

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Gallia Tour narration panel")
    parser.add_argument("--port", type=int, default=8799,
                        help="HTTP server port (default: 8799)")
    parser.add_argument("--width", type=int, default=480,
                        help="Panel width in pixels (default: 480)")
    args = parser.parse_args()

    panel = NarrationPanel(width=args.width)
    panel.start_server(port=args.port)
    print(f"Panel server listening on http://127.0.0.1:{args.port}")
    panel.root.mainloop()
