/**
 * =============================================================================
 * QWHPI — Quebec Weekly Housing Price Index
 * Author  : Simon-Pierre Boucher
 * Contact : contact@spboucher.ai
 * File    : web/components/CommandPalette.tsx
 * Purpose : ⌘K command palette — fuzzy jump to any series or page,
 *           full keyboard navigation, zero dependencies.
 * =============================================================================
 */
"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { fetchGeographies, type GeographyNode } from "../lib/api";

interface Item {
  label: string;
  hint: string;
  href: string;
}

const PAGES: Item[] = [
  { label: "Overview", hint: "page", href: "/" },
  { label: "Explore", hint: "page", href: "/explore" },
  { label: "Compare", hint: "page", href: "/compare" },
  { label: "Map", hint: "page", href: "/map" },
  { label: "Methodology", hint: "page", href: "/methodology" },
  { label: "API docs", hint: "page", href: "/api-docs" },
];
const TYPES = ["all", "unifamilial", "condo", "plex"];

function norm(s: string): string {
  return s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase();
}

export default function CommandPalette() {
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [q, setQ] = useState("");
  const [sel, setSel] = useState(0);
  const [geos, setGeos] = useState<GeographyNode[]>([]);
  const inputRef = useRef<HTMLInputElement>(null);
  const listRef = useRef<HTMLUListElement>(null);

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setOpen((v) => !v);
      } else if (e.key === "Escape") {
        setOpen(false);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  useEffect(() => {
    if (open) {
      setQ("");
      setSel(0);
      setTimeout(() => inputRef.current?.focus(), 30);
      if (!geos.length)
        fetchGeographies().then((g) => setGeos(g.published_series)).catch(() => {});
    }
  }, [open, geos.length]);

  const items = useMemo<Item[]>(() => {
    const series: Item[] = geos.flatMap((g) =>
      g.property_types.filter((t) => TYPES.includes(t)).map((t) => ({
        label: `${g.geography_name} · ${t}`,
        hint: g.geography_level,
        href: `/explore?geography=${g.geography_id}&type=${t}`,
      })));
    const all = [...PAGES, ...series];
    if (!q) return all.slice(0, 12);
    const tokens = norm(q).split(/\s+/).filter(Boolean);
    return all
      .filter((i) => {
        const hay = norm(i.label + " " + i.hint);
        return tokens.every((t) => hay.includes(t));
      })
      .slice(0, 12);
  }, [geos, q]);

  const go = useCallback((item: Item) => {
    setOpen(false);
    router.push(item.href);
  }, [router]);

  const onInputKey = (e: React.KeyboardEvent) => {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setSel((s) => Math.min(s + 1, items.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setSel((s) => Math.max(s - 1, 0));
    } else if (e.key === "Enter" && items[sel]) {
      go(items[sel]);
    }
  };

  useEffect(() => {
    listRef.current?.children[sel]?.scrollIntoView({ block: "nearest" });
  }, [sel]);

  if (!open) return null;

  return (
    <div className="palette-backdrop" onClick={() => setOpen(false)}
         role="dialog" aria-modal="true" aria-label="Command palette">
      <div className="palette" onClick={(e) => e.stopPropagation()}>
        <input
          ref={inputRef}
          value={q}
          onChange={(e) => { setQ(e.target.value); setSel(0); }}
          onKeyDown={onInputKey}
          placeholder="Jump to a series or page…  (e.g. montreal condo)"
          aria-label="Search series and pages"
          className="palette-input"
        />
        <ul ref={listRef} className="palette-list" role="listbox">
          {items.map((it, i) => (
            <li key={it.href + it.label} role="option" aria-selected={i === sel}>
              <button
                className={"palette-item" + (i === sel ? " active" : "")}
                onMouseEnter={() => setSel(i)}
                onClick={() => go(it)}
              >
                <span>{it.label}</span>
                <span className="palette-hint">{it.hint}</span>
              </button>
            </li>
          ))}
          {!items.length && (
            <li className="palette-empty">No match — try a region or city name</li>
          )}
        </ul>
        <div className="palette-foot">
          <span>↑↓ navigate</span><span>↵ open</span><span>esc close</span>
        </div>
      </div>
    </div>
  );
}
