"use client";

import { Command } from "cmdk";
import { useRouter } from "next/navigation";
import { useEffect, useRef, useState } from "react";
import { contact } from "@/lib/portfolio";

type PaletteAction =
  | { kind: "scroll"; targetId: "work" | "capabilities" | "operator" | "contact" }
  | { kind: "route"; href: "/blog/" }
  | { kind: "copy-email" }
  | { kind: "external"; href: string };

const commands: {
  label: string;
  hint: string;
  keywords: string[];
  action: PaletteAction;
}[] = [
  {
    label: "Go to Work",
    hint: "#work",
    keywords: ["projects", "dossiers", "selected work"],
    action: { kind: "scroll", targetId: "work" },
  },
  {
    label: "Go to Capabilities",
    hint: "#capabilities",
    keywords: ["skills", "systems", "kernel"],
    action: { kind: "scroll", targetId: "capabilities" },
  },
  {
    label: "Go to Operator",
    hint: "#operator",
    keywords: ["profile", "identity", "honors"],
    action: { kind: "scroll", targetId: "operator" },
  },
  {
    label: "Go to Contact",
    hint: "#contact",
    keywords: ["email", "ssh", "signal"],
    action: { kind: "scroll", targetId: "contact" },
  },
  {
    label: "Open Field Notes",
    hint: "/blog/",
    keywords: ["blog", "notes", "archive"],
    action: { kind: "route", href: "/blog/" },
  },
  {
    label: "Copy Email",
    hint: "copy",
    keywords: [contact.email, "mail", "contact"],
    action: { kind: "copy-email" },
  },
  {
    label: "Open Git profile",
    hint: "git",
    keywords: ["source", "forge", "code"],
    action: { kind: "external", href: contact.git },
  },
  {
    label: "Open LinkedIn",
    hint: "in",
    keywords: ["profile", "social", "linkedin"],
    action: { kind: "external", href: contact.linkedIn },
  },
];

export function CommandPalette() {
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [pendingAction, setPendingAction] = useState<PaletteAction | null>(null);
  const lastFocusedElement = useRef<HTMLElement | null>(null);
  const wasOpen = useRef(false);

  useEffect(() => {
    function rememberFocus() {
      lastFocusedElement.current =
        document.activeElement instanceof HTMLElement ? document.activeElement : null;
    }

    function onKeyDown(event: KeyboardEvent) {
      if (event.key.toLowerCase() !== "k" || (!event.metaKey && !event.ctrlKey)) {
        return;
      }

      event.preventDefault();
      rememberFocus();
      setOpen((current) => !current);
    }

    function onPaletteEvent() {
      rememberFocus();
      setOpen(true);
    }

    window.addEventListener("keydown", onKeyDown);
    window.addEventListener("blacksite:palette", onPaletteEvent);

    return () => {
      window.removeEventListener("keydown", onKeyDown);
      window.removeEventListener("blacksite:palette", onPaletteEvent);
    };
  }, []);

  useEffect(() => {
    if (wasOpen.current && !open) {
      lastFocusedElement.current?.focus();
    }

    wasOpen.current = open;
  }, [open]);

  useEffect(() => {
    if (!pendingAction) {
      return;
    }

    let cancelled = false;

    async function runAction(action: PaletteAction) {
      if (action.kind === "scroll") {
        document.getElementById(action.targetId)?.scrollIntoView({ block: "start" });
      }

      if (action.kind === "route") {
        router.push(action.href);
      }

      if (action.kind === "copy-email") {
        try {
          await navigator.clipboard.writeText(contact.email);
        } catch {
          // Clipboard failures should not strand the command dialog open.
        }
      }

      if (action.kind === "external") {
        window.open(action.href, "_blank", "noopener");
      }

      if (!cancelled) {
        setOpen(false);
        setPendingAction(null);
      }
    }

    void runAction(pendingAction);

    return () => {
      cancelled = true;
    };
  }, [pendingAction, router]);

  return (
    <Command.Dialog
      open={open}
      onOpenChange={setOpen}
      label="Signal Blacksite command palette"
      loop
      className="border border-blacksite-line bg-blacksite-surface text-blacksite-text shadow-[0_32px_120px_rgba(0,0,0,0.62)]"
      overlayClassName="fixed inset-0 z-[90] bg-black/72 backdrop-blur-sm"
      contentClassName="fixed left-1/2 top-[12vh] z-[100] w-[calc(100vw-2rem)] max-w-2xl -translate-x-1/2 overflow-hidden rounded-lg border border-blacksite-line bg-blacksite-surface shadow-[0_32px_120px_rgba(0,0,0,0.62)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-signal-cyan"
    >
      <div className="border-b border-blacksite-line px-4 py-3 sm:px-5">
        <p className="section-label">COMMAND PALETTE</p>
        <Command.Input
          autoFocus
          placeholder="Command…"
          className="mt-3 w-full bg-transparent font-mono text-base text-blacksite-text outline-none placeholder:text-blacksite-muted focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-signal-cyan sm:text-lg"
        />
      </div>

      <Command.List className="max-h-[min(24rem,60vh)] overflow-y-auto p-2 [scroll-padding-block:0.5rem]">
        <Command.Empty className="px-3 py-8 text-center font-mono text-xs uppercase tracking-[0.16em] text-blacksite-muted">
          No matching command.
        </Command.Empty>

        <Command.Group
          heading="Navigation"
          className="[&_[cmdk-group-heading]]:px-3 [&_[cmdk-group-heading]]:pb-2 [&_[cmdk-group-heading]]:pt-3 [&_[cmdk-group-heading]]:font-mono [&_[cmdk-group-heading]]:text-[11px] [&_[cmdk-group-heading]]:uppercase [&_[cmdk-group-heading]]:tracking-[0.16em] [&_[cmdk-group-heading]]:text-blacksite-muted"
        >
          {commands.map((command) => (
            <Command.Item
              key={command.label}
              value={command.label}
              keywords={command.keywords}
              onSelect={() => setPendingAction(command.action)}
              className="group flex cursor-pointer select-none items-center justify-between gap-4 rounded-md border border-transparent px-3 py-3 font-mono text-sm text-blacksite-text outline-none transition-colors data-[selected=true]:border-signal-cyan/60 data-[selected=true]:bg-signal-cyan/12 data-[selected=true]:text-signal-cyan data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50"
            >
              <span>{command.label}</span>
              <kbd className="shrink-0 rounded border border-blacksite-line bg-blacksite-bg2 px-2 py-1 text-[10px] uppercase tracking-[0.16em] text-blacksite-muted transition-colors group-data-[selected=true]:border-signal-cyan/50 group-data-[selected=true]:text-signal-cyan">
                {command.hint}
              </kbd>
            </Command.Item>
          ))}
        </Command.Group>
      </Command.List>

      <div className="flex items-center justify-between border-t border-blacksite-line px-4 py-3 font-mono text-[11px] uppercase tracking-[0.16em] text-blacksite-muted sm:px-5">
        <span>↑↓ select</span>
        <span>Enter run · Esc close</span>
      </div>
    </Command.Dialog>
  );
}
