"use client";

/**
 * CommandPalette — Cmd+K / Ctrl+K global quick-launcher for the admin.
 *
 * Behavior:
 *   - Toggled with Cmd+K (mac) or Ctrl+K (win/linux) on `document`.
 *   - Closes on Escape, on backdrop click, or after a navigation.
 *   - Fuzzy case-insensitive match on `label` / `category` / `keywords`.
 *   - Top 8 results. Renders null when closed (no DOM noise).
 *   - Keyboard: ↑/↓ to move, Enter to select, type to filter.
 *
 * Self-contained: does not read from the sidebar, does not depend on any
 * server data. The static list lives in `./command-palette-data.ts`.
 *
 * The component is intentionally NOT mounted in the admin layout by this
 * file. The main thread / sidebar agent wires it in once it's reviewed.
 */

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import {
  BarChart3,
  Clock,
  Command,
  CreditCard,
  Droplets,
  FileText,
  LayoutDashboard,
  LucideIcon,
  Map as MapIcon,
  MapPin,
  Megaphone,
  Package,
  Plug,
  PlusCircle,
  Puzzle,
  Receipt,
  RefreshCw,
  Route,
  ScrollText,
  Search,
  Send,
  Settings,
  ShoppingCart,
  Sparkles,
  Store,
  Tag,
  Truck,
  Upload,
  UserPlus,
  Users,
  Wallet,
} from "lucide-react";
import { PALETTE_ENTRIES, type PaletteEntry } from "./command-palette-data";

const MAX_RESULTS = 8;

// ---------------------------------------------------------------------------
// Icon registry
// ---------------------------------------------------------------------------

const ICON_MAP: Record<string, LucideIcon> = {
  // Pages
  LayoutDashboard,
  Command,
  ShoppingCart,
  MapPin,
  Package,
  Truck,
  Send,
  Megaphone,
  FileText,
  Users,
  ScrollText,
  Store,
  Upload,
  Sparkles,
  Clock,
  Droplets,
  Route,
  BarChart3,
  Receipt,
  Settings,
  Tag,
  CreditCard,
  Plug,
  Wallet,
  Puzzle,
  // Quick actions
  PlusCircle,
  UserPlus,
  RefreshCw,
  // Misc / fallbacks
  Search,
  Map: MapIcon,
};

// ---------------------------------------------------------------------------
// Filtering / scoring
// ---------------------------------------------------------------------------

function scoreEntry(entry: PaletteEntry, query: string): number {
  if (!query) return 1;
  const q = query.toLowerCase();
  const label = entry.label.toLowerCase();
  const category = entry.category.toLowerCase();

  let score = 0;
  if (label === q) score += 100;
  else if (label.startsWith(q)) score += 50;
  else if (label.includes(q)) score += 25;

  if (category.toLowerCase().includes(q)) score += 10;
  if (entry.keywords?.some((k) => k.toLowerCase().includes(q))) score += 5;

  // Quick actions get a small boost when no specific match (so they surface
  // on the empty query list, alongside the first batch of pages).
  if (!query && entry.type === "action") score = 0.5;
  if (!query && entry.type === "page") score = 1 - entry.label.length * 0.001;

  return score;
}

function filterEntries(query: string): PaletteEntry[] {
  const scored: { entry: PaletteEntry; score: number }[] = [];
  for (const e of PALETTE_ENTRIES) {
    const score = scoreEntry(e, query);
    if (score > 0) {
      scored.push({ entry: e, score });
    }
  }
  scored.sort((a, b) => b.score - a.score);
  return scored.slice(0, MAX_RESULTS).map((r) => r.entry);
}

// ---------------------------------------------------------------------------
// Highlight helper
// ---------------------------------------------------------------------------

function HighlightedText({ text, query }: { text: string; query: string }) {
  if (!query) return <>{text}</>;
  const q = query.toLowerCase();
  const idx = text.toLowerCase().indexOf(q);
  if (idx === -1) return <>{text}</>;
  return (
    <>
      {text.slice(0, idx)}
      <mark
        style={{
          background: "transparent",
          color: "var(--admin-primary)",
          fontWeight: 600,
          padding: 0,
        }}
      >
        {text.slice(idx, idx + query.length)}
      </mark>
      {text.slice(idx + query.length)}
    </>
  );
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export default function CommandPalette() {
  const [open, setOpen] = useState(false);
  const [toggleCount, setToggleCount] = useState(0);

  // Open/close on Cmd+K / Ctrl+K. Toggle so the same shortcut closes it.
  useEffect(() => {
    function onKeyDown(e: KeyboardEvent) {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setOpen((o) => !o);
        setToggleCount((c) => c + 1);
      }
    }
    document.addEventListener("keydown", onKeyDown);
    return () => document.removeEventListener("keydown", onKeyDown);
  }, []);

  if (!open) return null;
  return <CommandPaletteDialog key={toggleCount} onClose={() => setOpen(false)} />;
}

function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
  const [query, setQuery] = useState("");
  const [selected, setSelected] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const dialogRef = useRef<HTMLDialogElement>(null);
  const router = useRouter();

  // Native <dialog> handles focus trapping, ESC, and the backdrop.
  useEffect(() => {
    const dialog = dialogRef.current;
    if (!dialog) return;
    if (!dialog.open) dialog.showModal();
    const raf = requestAnimationFrame(() => inputRef.current?.focus());
    const onCancel = (e: Event) => {
      e.preventDefault();
      onClose();
    };
    dialog.addEventListener("cancel", onCancel);
    return () => {
      cancelAnimationFrame(raf);
      dialog.removeEventListener("cancel", onCancel);
    };
  }, [onClose]);

  // Filtering
  const results = useMemo(() => filterEntries(query), [query]);

  // Always render a valid selection index (clamped to results length).
  const safeSelected =
    results.length === 0 ? 0 : Math.min(selected, results.length - 1);

  const navigate = useCallback(
    (href: string) => {
      onClose();
      router.push(href);
    },
    [router, onClose]
  );

  // In-input keyboard nav. Attached to the input itself so it works whether
  // the user is typing or the input just has focus.
  const handleInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      if (results.length === 0) return;
      setSelected((s) => (s + 1) % results.length);
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      if (results.length === 0) return;
      setSelected((s) => (s - 1 + results.length) % results.length);
    } else if (e.key === "Enter") {
      e.preventDefault();
      const entry = results[safeSelected];
      if (entry) navigate(entry.href);
    }
  };

  return (
    <dialog
      ref={dialogRef}
      aria-label="Command palette"
      className="m-0 p-0 w-full h-full max-w-none max-h-full bg-transparent"
      style={{
        backgroundColor: "transparent",
        animation: "cp-fade-in 180ms ease-out",
      }}
    >
      <style>{`
        @keyframes cp-fade-in {
          from { opacity: 0; }
          to   { opacity: 1; }
        }
        @keyframes cp-scale-in {
          from { opacity: 0; }
          to   { opacity: 1; }
        }
        @media (prefers-reduced-motion: reduce) {
          @keyframes cp-fade-in { from { opacity: 0; } to { opacity: 1; } }
          @keyframes cp-scale-in { from { opacity: 0; } to { opacity: 1; } }
        }
      `}</style>

      <div
        style={{
          position: "fixed",
          inset: 0,
          zIndex: 60,
          backgroundColor: "rgba(26, 24, 20, 0.4)",
          backdropFilter: "blur(4px)",
          WebkitBackdropFilter: "blur(4px)",
          display: "flex",
          alignItems: "flex-start",
          justifyContent: "center",
          paddingTop: "15vh",
        }}
      >
        <div
          style={{
            width: "100%",
            maxWidth: "36rem",
            margin: "0 1rem",
          backgroundColor: "var(--admin-card-bg)",
          border: "1px solid var(--admin-border)",
          borderRadius: "var(--admin-radius-lg)",
          boxShadow: "var(--admin-shadow-lg)",
          overflow: "hidden",
          animation: "cp-scale-in 180ms ease-out",
          display: "flex",
          flexDirection: "column",
        }}
      >
        {/* Search input row */}
        <div
          style={{
            display: "flex",
            alignItems: "center",
            gap: "0.75rem",
            padding: "0.875rem 1rem",
            borderBottom: "1px solid var(--admin-border)",
          }}
        >
          <Search
            size={18}
            style={{ color: "var(--admin-text-muted)", flexShrink: 0 }}
            aria-hidden="true"
          />
          <input
            ref={inputRef}
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            onKeyDown={handleInputKeyDown}
            placeholder="Search pages, actions, anything…"
            aria-label="Search command palette"
            spellCheck={false}
            autoComplete="off"
            className="flex-1 min-w-0 border-none outline-none focus-visible:outline-2 focus-visible:outline-[var(--color-accent)] focus-visible:outline-offset-2 bg-transparent text-base"
            style={{
              lineHeight: 1.4,
              color: "var(--admin-text-primary)",
              fontFamily: "inherit",
            }}
            // Restore the focus ring only for keyboard users. Mouse clicks
            // hide it; tabbing into the input keeps a visible outline.
            onFocus={(e) => {
              e.currentTarget.style.outline = "2px solid var(--admin-accent)";
              e.currentTarget.style.outlineOffset = "2px";
            }}
            onBlur={(e) => {
              e.currentTarget.style.outline = "none";
              e.currentTarget.style.outlineOffset = "0";
            }}
          />
        </div>

        {/* Results */}
        <ul
          aria-label="Results"
          className="list-none p-0 m-0"
          style={{
            maxHeight: "60vh",
            overflowY: "auto",
            padding: "0.375rem",
          }}
        >
          {results.length === 0 ? (
            <div
              style={{
                padding: "2rem 1rem",
                textAlign: "center",
                color: "var(--admin-text-muted)",
                fontSize: "0.875rem",
              }}
            >
              No results for &ldquo;{query}&rdquo;
            </div>
          ) : (
            results.map((entry, i) => {
              const Icon = ICON_MAP[entry.iconName] ?? Search;
              const isSelected = i === safeSelected;
              return (
                <li key={entry.id} className="list-none">
                  <button
                    type="button"
                    aria-current={isSelected ? "true" : undefined}
                    onClick={() => navigate(entry.href)}
                    onMouseEnter={() => setSelected(i)}
                    style={{
                      display: "flex",
                      alignItems: "center",
                      gap: "0.75rem",
                      width: "100%",
                      padding: "0.625rem 0.75rem",
                      borderRadius: "var(--admin-radius-md)",
                      border: "none",
                      background: isSelected
                        ? "var(--admin-primary-soft)"
                        : "transparent",
                      color: isSelected
                        ? "var(--admin-primary)"
                        : "var(--admin-text-primary)",
                      cursor: "pointer",
                      textAlign: "left",
                      fontSize: "0.875rem",
                      lineHeight: 1.3,
                      fontFamily: "inherit",
                      transition:
                        "background-color 80ms ease-out, color 80ms ease-out",
                    }}
                  >
                    <Icon
                      size={16}
                      style={{
                        flexShrink: 0,
                        opacity: isSelected ? 1 : 0.7,
                      }}
                      aria-hidden="true"
                    />
                    <span
                      style={{
                        flex: 1,
                        minWidth: 0,
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                        whiteSpace: "nowrap",
                        fontWeight: 500,
                      }}
                    >
                      <HighlightedText text={entry.label} query={query} />
                    </span>
                    <span
                      style={{
                        fontSize: "0.75rem",
                        textTransform: "uppercase",
                        letterSpacing: "0.05em",
                        color: "var(--admin-text-muted)",
                        fontWeight: 500,
                        flexShrink: 0,
                      }}
                    >
                      {entry.category}
                    </span>
                  </button>
                </li>
              );
            })
          )}
        </ul>

        {/* Footer hint */}
        <div
          style={{
            padding: "0.5rem 1rem 0.625rem",
            borderTop: "1px solid var(--admin-border)",
            fontSize: "0.75rem",
            color: "var(--admin-text-muted)",
            textAlign: "center",
            letterSpacing: "0.02em",
            userSelect: "none",
          }}
        >
          ↑↓ to navigate &nbsp;·&nbsp; ↵ to select &nbsp;·&nbsp; esc to close
        </div>
      </div>
      </div>
    </dialog>
  );
}
