"use client";

import {
  useEffect,
  useMemo,
  useRef,
  useState,
  type ReactNode,
} from "react";
import { IconSearch, IconArrowRight } from "@/components/icons";

export type Command = {
  id: string;
  group: string;
  label: string;
  hint?: string;
  icon?: ReactNode;
  shortcut?: string;
  keywords?: string[];
  action: () => void | Promise<void>;
};

type Props = {
  commands: Command[];
  placeholder?: string;
};

export function CommandPalette({
  commands,
  placeholder = "Tape une commande ou cherche…",
}: Props) {
  const [open, setOpen] = useState(false);
  const [query, setQuery] = useState("");
  const [selected, setSelected] = useState(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLDivElement>(null);

  // Cmd/Ctrl+K → toggle (avec reset query+effectiveSelected à l'ouverture, géré
  // dans le même handler pour éviter setState-in-effect).
  useEffect(() => {
    function handleKey(e: KeyboardEvent) {
      const isMeta = e.metaKey || e.ctrlKey;
      if (isMeta && (e.key === "k" || e.key === "K")) {
        e.preventDefault();
        setOpen((o) => {
          if (!o) {
            // Ouverture : reset
            setQuery("");
            setSelected(0);
          }
          return !o;
        });
      }
    }
    document.addEventListener("keydown", handleKey);
    return () => document.removeEventListener("keydown", handleKey);
  }, []);

  // Lock du scroll body + focus input quand open
  useEffect(() => {
    if (!open) return;
    requestAnimationFrame(() => inputRef.current?.focus());
    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    return () => {
      document.body.style.overflow = previousOverflow;
    };
  }, [open]);

  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    if (!q) return commands;
    return commands.filter((c) => {
      const haystack = [c.label, c.group, c.hint ?? "", ...(c.keywords ?? [])]
        .join(" ")
        .toLowerCase();
      return haystack.includes(q);
    });
  }, [commands, query]);

  // Borne dérivée — pas de setState in effect, juste un clamp au render.
  const effectiveSelected =
    filtered.length === 0 ? 0 : Math.min(selected, filtered.length - 1);

  // Scroll into view (lecture du DOM uniquement, pas de setState)
  useEffect(() => {
    if (!open || !listRef.current) return;
    const el = listRef.current.querySelector<HTMLElement>(
      `[data-cmd-index="${effectiveSelected}"]`,
    );
    el?.scrollIntoView({ block: "nearest" });
  }, [effectiveSelected, open]);

  function execute(idx: number) {
    const cmd = filtered[idx];
    if (!cmd) return;
    setOpen(false);
    Promise.resolve(cmd.action()).catch((e) => {
      console.error("[command-palette] action failed:", e);
    });
  }

  function handleInputKey(e: React.KeyboardEvent<HTMLInputElement>) {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setSelected((s) => Math.min(filtered.length - 1, s + 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setSelected((s) => Math.max(0, s - 1));
    } else if (e.key === "Enter") {
      e.preventDefault();
      execute(effectiveSelected);
    } else if (e.key === "Escape") {
      e.preventDefault();
      setOpen(false);
    }
  }

  if (!open) return null;

  // Group filtered commands
  const groups: { name: string; items: Array<{ cmd: Command; index: number }> }[] = [];
  for (let i = 0; i < filtered.length; i++) {
    const cmd = filtered[i];
    let group = groups.find((g) => g.name === cmd.group);
    if (!group) {
      group = { name: cmd.group, items: [] };
      groups.push(group);
    }
    group.items.push({ cmd, index: i });
  }

  return (
    <div
      className="fixed inset-0 z-[80] flex items-start justify-center px-4 pt-[12vh] mf-fade-in"
      role="presentation"
    >
      <div
        className="absolute inset-0 bg-foreground/40 backdrop-blur-[2px]"
        onClick={() => setOpen(false)}
      />

      <div
        role="dialog"
        aria-modal="true"
        aria-label="Commandes"
        className="relative z-10 w-full max-w-lg rounded-xl bg-surface border border-border shadow-lg overflow-hidden"
      >
        <div className="flex items-center gap-3 border-b border-border px-4 py-3">
          <IconSearch size={16} className="text-muted-foreground" />
          <input
            ref={inputRef}
            type="text"
            value={query}
            onChange={(e) => {
              setQuery(e.target.value);
              setSelected(0);
            }}
            onKeyDown={handleInputKey}
            placeholder={placeholder}
            className="flex-1 bg-transparent text-sm text-foreground focus:outline-none placeholder:text-subtle-foreground"
            aria-autocomplete="list"
          />
          <kbd className="rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground">
            esc
          </kbd>
        </div>

        <div ref={listRef} className="max-h-80 overflow-y-auto py-2">
          {groups.length === 0 ? (
            <p className="py-8 text-center text-sm text-muted-foreground">
              Aucun résultat pour « {query} ».
            </p>
          ) : (
            groups.map((g) => (
              <div key={g.name} className="mb-1">
                <div className="px-3 py-1 text-[10px] font-medium uppercase tracking-wider text-subtle-foreground">
                  {g.name}
                </div>
                {g.items.map(({ cmd, index }) => {
                  const isSelected = index === effectiveSelected;
                  return (
                    <button
                      key={cmd.id}
                      type="button"
                      data-cmd-index={index}
                      onClick={() => execute(index)}
                      onMouseEnter={() => setSelected(index)}
                      className={[
                        "flex w-full items-center gap-3 px-3 py-2 text-sm text-left transition-colors",
                        isSelected
                          ? "bg-accent-subtle text-accent"
                          : "text-foreground hover:bg-surface-2",
                      ].join(" ")}
                    >
                      {cmd.icon && (
                        <span
                          className={
                            isSelected ? "text-accent" : "text-muted-foreground"
                          }
                        >
                          {cmd.icon}
                        </span>
                      )}
                      <span className="flex-1 truncate">{cmd.label}</span>
                      {cmd.hint && (
                        <span className="text-xs text-muted-foreground">
                          {cmd.hint}
                        </span>
                      )}
                      {cmd.shortcut ? (
                        <kbd className="rounded border border-border bg-surface-2 px-1.5 py-0.5 font-mono text-[10px]">
                          {cmd.shortcut}
                        </kbd>
                      ) : (
                        isSelected && (
                          <IconArrowRight
                            size={12}
                            className="text-accent shrink-0"
                          />
                        )
                      )}
                    </button>
                  );
                })}
              </div>
            ))
          )}
        </div>

        <div className="flex items-center justify-between gap-3 border-t border-border bg-surface-2 px-4 py-2 text-[10px] text-muted-foreground">
          <span>
            <kbd className="rounded border border-border bg-surface px-1 py-0.5 font-mono">
              ↑↓
            </kbd>{" "}
            naviguer ·{" "}
            <kbd className="rounded border border-border bg-surface px-1 py-0.5 font-mono">
              ↵
            </kbd>{" "}
            ouvrir
          </span>
          <span>
            {filtered.length} commande{filtered.length > 1 ? "s" : ""}
          </span>
        </div>
      </div>
    </div>
  );
}
