"use client";

import { motion, AnimatePresence } from "framer-motion";
import { Check, Palette } from "lucide-react";
import { useEffect, useRef, useState } from "react";

type ThemeId = "aurora" | "neon" | "obsidian" | "ion";

interface ThemeOption {
  id: ThemeId;
  label: string;
  hint: string;
  dots: [string, string, string];
}

const STORAGE_KEY = "mm-theme";
const DEFAULT_THEME: ThemeId = "aurora";

// Swatch hexes are literal previews of each palette (they must NOT follow the
// active theme). Source of truth: the [data-theme] blocks in globals.css.
const THEMES: ThemeOption[] = [
  { id: "aurora",   label: "Aurora",   hint: "gold · magenta · violet", dots: ["#f5b829", "#f0398b", "#a855f7"] },
  { id: "neon",     label: "Neon",     hint: "cyan · pink · lime",      dots: ["#22d3ee", "#f43f8e", "#a3e635"] },
  { id: "obsidian", label: "Obsidian", hint: "gold · copper · sage",    dots: ["#d4af37", "#c97c5e", "#8fb08a"] },
  { id: "ion",      label: "Ion",      hint: "blue · cyan · mint",      dots: ["#3b82f6", "#22d3ee", "#34d399"] },
];

function isThemeId(value: string | null | undefined): value is ThemeId {
  return THEMES.some((t) => t.id === value);
}

function Dots({ colors, size = 8 }: { colors: [string, string, string]; size?: number }) {
  return (
    <span className="inline-flex items-center gap-1" aria-hidden="true">
      {colors.map((c) => (
        <span
          key={c}
          className="rounded-full"
          style={{ width: size, height: size, background: c, boxShadow: `0 0 6px ${c}55` }}
        />
      ))}
    </span>
  );
}

export default function ThemeSwitcher() {
  const [open, setOpen] = useState(false);
  const [theme, setTheme] = useState<ThemeId>(DEFAULT_THEME);
  const wrapRef = useRef<HTMLDivElement>(null);

  // The pre-paint script in layout.tsx already set data-theme — sync after mount.
  useEffect(() => {
    const current = document.documentElement.dataset.theme;
    if (isThemeId(current)) setTheme(current);
  }, []);

  // Close on outside click / Escape while open.
  useEffect(() => {
    if (!open) return;
    const onPointerDown = (e: PointerEvent) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target as Node)) setOpen(false);
    };
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === "Escape") setOpen(false);
    };
    window.addEventListener("pointerdown", onPointerDown);
    window.addEventListener("keydown", onKeyDown);
    return () => {
      window.removeEventListener("pointerdown", onPointerDown);
      window.removeEventListener("keydown", onKeyDown);
    };
  }, [open]);

  function applyTheme(id: ThemeId) {
    document.documentElement.dataset.theme = id;
    try {
      localStorage.setItem(STORAGE_KEY, id);
    } catch {
      /* storage unavailable (private mode) — theme still applies this session */
    }
    setTheme(id);
    setOpen(false);
  }

  const active = THEMES.find((t) => t.id === theme) ?? THEMES[0];

  return (
    <div ref={wrapRef} className="relative">
      <button
        onClick={() => setOpen((o) => !o)}
        aria-haspopup="listbox"
        aria-expanded={open}
        aria-label={`Theme: ${active.label}`}
        title="Switch theme"
        className="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg border border-[var(--panel-border)] text-[12px] text-[var(--fg-dim)] hover:text-[var(--fg)] hover:border-[var(--panel-border-hot)] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[var(--gold)] active:translate-y-px transition"
      >
        <Palette size={14} style={{ color: "var(--gold)" }} />
        <span className="hidden lg:inline">{active.label}</span>
        <Dots colors={active.dots} size={6} />
      </button>

      <AnimatePresence>
        {open && (
          <motion.div
            initial={{ opacity: 0, y: -4, scale: 0.98 }}
            animate={{ opacity: 1, y: 0, scale: 1 }}
            exit={{ opacity: 0, y: -4, scale: 0.98 }}
            transition={{ duration: 0.16, ease: "easeOut" }}
            role="listbox"
            aria-label="Theme"
            className="absolute right-0 top-full mt-2 z-50 w-[220px] rounded-[10px] border border-[var(--line-soft)] p-1.5"
            style={{ background: "var(--bg-card)", boxShadow: "var(--shadow-2)" }}
          >
            <div className="px-2.5 pt-1.5 pb-2 sidebar-section-label">Theme</div>
            {THEMES.map((t) => {
              const selected = t.id === theme;
              return (
                <button
                  key={t.id}
                  role="option"
                  aria-selected={selected}
                  onClick={() => applyTheme(t.id)}
                  className="w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md text-left hover:bg-[color-mix(in_srgb,var(--gold)_8%,transparent)] focus-visible:outline focus-visible:outline-1 focus-visible:outline-[var(--gold)] transition"
                  style={{
                    background: selected ? "var(--bg-elev)" : undefined,
                    border: `1px solid ${selected ? "var(--line)" : "transparent"}`,
                  }}
                >
                  <Dots colors={t.dots} />
                  <span className="flex-1 min-w-0">
                    <span className="block text-[12.5px]" style={{ color: "var(--cream)", fontFamily: "'Bricolage Grotesque', sans-serif", fontWeight: 500 }}>
                      {t.label}
                    </span>
                    <span className="block text-[10px] truncate" style={{ color: "var(--cream-mute)" }}>
                      {t.hint}
                    </span>
                  </span>
                  {selected && <Check size={13} style={{ color: "var(--gold)" }} />}
                </button>
              );
            })}
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}
