import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
import { useNavigate } from "@tanstack/react-router";
import {
  Activity,
  Building2,
  ChevronRight,
  FileText,
  HelpCircle,
  Loader2,
  Search,
  Truck,
  X,
} from "lucide-react";
import type { AuthPlatform } from "@/lib/auth";
import { getSession } from "@/lib/auth";
import {
  categoryLabel,
  searchApi,
  searchNavigation,
  type SearchCategory,
  type SearchHit,
  type SearchResponse,
} from "@/lib/search-api";
import { cn } from "@/lib/utils";

const DEBOUNCE_MS = 280;
const RECENT_KEY = (platform: AuthPlatform, email: string) =>
  `amanah-search-recent-${platform}-${email.toLowerCase()}`;

function iconFor(category: SearchCategory) {
  switch (category) {
    case "clients":
      return Building2;
    case "documents":
      return FileText;
    case "suppliers":
      return Truck;
    case "questions":
      return HelpCircle;
    case "activity":
      return Activity;
  }
}

function loadRecent(platform: AuthPlatform, email: string): string[] {
  try {
    const raw = localStorage.getItem(RECENT_KEY(platform, email));
    if (!raw) return [];
    const parsed = JSON.parse(raw) as string[];
    return Array.isArray(parsed) ? parsed.slice(0, 5) : [];
  } catch {
    return [];
  }
}

function saveRecent(platform: AuthPlatform, email: string, query: string) {
  const q = query.trim();
  if (q.length < 2) return;
  const prev = loadRecent(platform, email).filter((x) => x.toLowerCase() !== q.toLowerCase());
  localStorage.setItem(RECENT_KEY(platform, email), JSON.stringify([q, ...prev].slice(0, 5)));
}

export type SearchInputVariant = "header" | "page";

export function GlobalSearch({
  platform,
  className,
  variant = "header",
  initialQuery = "",
  onQueryCommit,
}: {
  platform: AuthPlatform;
  className?: string;
  /** header = compact header field with dropdown; page = larger search-page field */
  variant?: SearchInputVariant;
  /** Seed value (e.g. from URL on the search page) */
  initialQuery?: string;
  /** Called when Enter / clear should update page results without navigating away */
  onQueryCommit?: (q: string) => void;
}) {
  const navigate = useNavigate();
  const session = getSession(platform);
  const listId = useId();
  const rootRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);
  const abortRef = useRef<AbortController | null>(null);
  const reqIdRef = useRef(0);

  const isHeader = variant === "header";
  const [query, setQuery] = useState(initialQuery);
  const [focused, setFocused] = useState(false);
  const [open, setOpen] = useState(false);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [data, setData] = useState<SearchResponse | null>(null);
  const [activeIndex, setActiveIndex] = useState(-1);
  const [recent, setRecent] = useState<string[]>([]);

  useEffect(() => {
    setQuery(initialQuery);
  }, [initialQuery]);

  const placeholder =
    platform === "firm" ? "Search clients, invoices..." : "Search your documents...";
  const shortcutLabel = useMemo(() => {
    if (typeof navigator === "undefined") return "⌘K";
    return /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) ? "⌘K" : "Ctrl K";
  }, []);

  const flatHits = useMemo(() => {
    if (!data) return [] as SearchHit[];
    const order: SearchCategory[] = ["clients", "documents", "suppliers", "questions", "activity"];
    const items: SearchHit[] = [];
    for (const key of order) {
      const group = data.categories[key];
      if (group) items.push(...group);
    }
    return items.length ? items : data.items;
  }, [data]);

  const runSearch = useCallback(
    async (q: string) => {
      if (!session?.email || !isHeader) return;
      const trimmed = q.trim();
      if (trimmed.length < 1) {
        setData(null);
        setLoading(false);
        setError(null);
        return;
      }

      abortRef.current?.abort();
      const controller = new AbortController();
      abortRef.current = controller;
      const reqId = ++reqIdRef.current;
      setLoading(true);
      setError(null);

      try {
        const result = await searchApi(platform, session.email, trimmed, {
          mode: "autocomplete",
          limit: 16,
          clientId: session.clientId,
          signal: controller.signal,
        });
        if (reqId !== reqIdRef.current) return;
        setData(result);
        setActiveIndex(result.total > 0 ? 0 : -1);
      } catch (err) {
        if ((err as Error).name === "AbortError") return;
        if (reqId !== reqIdRef.current) return;
        setError("Unable to search right now. Try again.");
        setData(null);
      } finally {
        if (reqId === reqIdRef.current) setLoading(false);
      }
    },
    [platform, session?.email, isHeader],
  );

  useEffect(() => {
    if (!isHeader || !open) return;
    const t = window.setTimeout(() => void runSearch(query), DEBOUNCE_MS);
    return () => window.clearTimeout(t);
  }, [query, open, runSearch, isHeader]);

  useEffect(() => {
    if (!isHeader) return;
    const onKey = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        inputRef.current?.focus();
        setOpen(true);
        setFocused(true);
        if (session?.email) setRecent(loadRecent(platform, session.email));
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [platform, session?.email, isHeader]);

  useEffect(() => {
    const onDown = (e: MouseEvent) => {
      if (!rootRef.current?.contains(e.target as Node)) {
        setOpen(false);
        setFocused(false);
        setActiveIndex(-1);
      }
    };
    document.addEventListener("mousedown", onDown);
    return () => document.removeEventListener("mousedown", onDown);
  }, []);

  const clearQuery = () => {
    setQuery("");
    setData(null);
    setError(null);
    setActiveIndex(-1);
    onQueryCommit?.("");
    inputRef.current?.focus();
  };

  const goToHit = (hit: SearchHit) => {
    if (session?.email) saveRecent(platform, session.email, query || hit.title);
    setOpen(false);
    setFocused(false);
    const nav = searchNavigation(platform, hit);
    void navigate({
      to: nav.to as never,
      params: nav.params as never,
      search: nav.search as never,
    });
  };

  const goToFullResults = (q: string) => {
    const trimmed = q.trim();
    if (!trimmed) return;
    if (session?.email) saveRecent(platform, session.email, trimmed);
    setOpen(false);
    setFocused(false);
    if (onQueryCommit) {
      onQueryCommit(trimmed);
      return;
    }
    void navigate({ to: "/search", search: { q: trimmed } as never });
  };

  const onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Escape") {
      e.preventDefault();
      if (open) {
        setOpen(false);
        setActiveIndex(-1);
      } else {
        inputRef.current?.blur();
        setFocused(false);
      }
      return;
    }
    if (isHeader && e.key === "ArrowDown") {
      e.preventDefault();
      if (!open) setOpen(true);
      setActiveIndex((i) => Math.min(i + 1, Math.max(flatHits.length - 1, 0)));
      return;
    }
    if (isHeader && e.key === "ArrowUp") {
      e.preventDefault();
      setActiveIndex((i) => Math.max(i - 1, 0));
      return;
    }
    if (e.key === "Enter") {
      e.preventDefault();
      if (isHeader && activeIndex >= 0 && flatHits[activeIndex]) {
        goToHit(flatHits[activeIndex]);
      } else {
        goToFullResults(query);
      }
    }
  };

  const hasText = query.length > 0;
  const showRecent = isHeader && open && !hasText && recent.length > 0;
  const showResultsPanel = isHeader && open && hasText;
  const showDropdown = showRecent || showResultsPanel;
  const categoryOrder: SearchCategory[] = ["clients", "documents", "suppliers", "questions", "activity"];

  return (
    <div
      ref={rootRef}
      className={cn(
        "relative",
        isHeader && "transition-[width] duration-200 ease-out",
        isHeader && (focused || open ? "w-[min(100%,340px)] lg:w-[360px]" : "w-[240px] lg:w-[260px]"),
        !isHeader && "w-full max-w-[650px]",
        className,
      )}
    >
      {/* Flex shell — single clear control, no native search cancel */}
      <div
        className={cn(
          "amanah-search-field flex items-center gap-2 rounded-lg border bg-surface transition-[border-color,box-shadow,background-color] duration-150",
          isHeader ? "h-9 px-2.5" : "h-11 px-3.5",
          focused || open
            ? "border-primary/35 shadow-[0_0_0_3px_oklch(0.759_0.162_122_/_0.18)]"
            : "border-border/90 hover:border-border",
        )}
      >
        <Search
          size={isHeader ? 15 : 17}
          className="shrink-0 text-muted-foreground"
          aria-hidden="true"
        />
        <input
          ref={inputRef}
          type="text"
          value={query}
          placeholder={placeholder}
          aria-label={placeholder}
          aria-expanded={isHeader ? showDropdown : undefined}
          aria-controls={isHeader ? listId : undefined}
          aria-autocomplete={isHeader ? "list" : undefined}
          autoComplete="off"
          spellCheck={false}
          role={isHeader ? "combobox" : "searchbox"}
          className={cn(
            "min-w-0 flex-1 bg-transparent text-foreground outline-none placeholder:text-muted-foreground",
            isHeader ? "text-[13px]" : "text-[14.5px]",
          )}
          onFocus={() => {
            setFocused(true);
            if (isHeader) {
              setOpen(true);
              if (session?.email) setRecent(loadRecent(platform, session.email));
            }
          }}
          onBlur={() => {
            // delay so dropdown clicks register
            window.setTimeout(() => {
              if (!rootRef.current?.contains(document.activeElement)) {
                setFocused(false);
              }
            }, 0);
          }}
          onChange={(e) => {
            setQuery(e.target.value);
            if (isHeader) setOpen(true);
          }}
          onKeyDown={onKeyDown}
        />
        {hasText ? (
          <button
            type="button"
            aria-label="Clear search"
            className="flex size-6 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
            onMouseDown={(e) => e.preventDefault()}
            onClick={clearQuery}
          >
            <X size={14} strokeWidth={2} />
          </button>
        ) : isHeader ? (
          <kbd className="pointer-events-none hidden shrink-0 select-none rounded border border-border/80 bg-muted/80 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground sm:inline-block">
            {shortcutLabel}
          </kbd>
        ) : null}
      </div>

      {showDropdown ? (
        <div
          id={listId}
          role="listbox"
          className="absolute top-[calc(100%+8px)] right-0 z-50 w-[min(100vw-1.5rem,400px)] overflow-hidden rounded-xl border border-border bg-popover shadow-[var(--shadow-panel)]"
        >
          {showRecent ? (
            <div className="p-2.5">
              <p className="px-2 py-1 text-[10px] font-bold tracking-[0.14em] text-muted-foreground uppercase">
                Recent searches
              </p>
              <ul>
                {recent.map((r) => (
                  <li key={r}>
                    <button
                      type="button"
                      className="flex w-full items-center gap-2 rounded-lg px-2 py-2 text-left text-[13px] hover:bg-muted/60"
                      onMouseDown={(e) => e.preventDefault()}
                      onClick={() => {
                        setQuery(r);
                        void runSearch(r);
                      }}
                    >
                      <Search size={14} className="shrink-0 text-muted-foreground" />
                      <span className="truncate">{r}</span>
                    </button>
                  </li>
                ))}
              </ul>
            </div>
          ) : loading && !data ? (
            <div className="flex items-center gap-2 px-4 py-5 text-[13px] text-muted-foreground">
              <Loader2 size={15} className="animate-spin" />
              Searching…
            </div>
          ) : error ? (
            <div className="px-4 py-5 text-center text-[13px] text-muted-foreground">
              <p className="font-medium text-foreground">Unable to search right now</p>
              <p className="mt-1 text-[12.5px]">{error}</p>
            </div>
          ) : data && data.total === 0 ? (
            <div className="px-4 py-5 text-center">
              <p className="text-[13px] font-medium text-foreground">
                No results for “{query.trim()}”
              </p>
              <button
                type="button"
                className="mt-3 text-[12.5px] font-semibold text-brand-foreground hover:underline"
                onMouseDown={(e) => e.preventDefault()}
                onClick={() => goToFullResults(query)}
              >
                Open full search →
              </button>
            </div>
          ) : data ? (
            <>
              <div className="max-h-[400px] overflow-y-auto py-1">
                {categoryOrder.map((cat) => {
                  const group = data.categories[cat];
                  if (!group?.length) return null;
                  return (
                    <div key={cat} className="py-1">
                      <p className="px-3 py-1.5 text-[10px] font-bold tracking-[0.14em] text-muted-foreground uppercase">
                        {categoryLabel(cat)}
                      </p>
                      <ul>
                        {group.map((hit) => {
                          const flatIdx = flatHits.findIndex((h) => h.id === hit.id);
                          const active = flatIdx === activeIndex;
                          const Icon = iconFor(hit.category);
                          return (
                            <li key={hit.id} role="option" aria-selected={active}>
                              <button
                                type="button"
                                className={cn(
                                  "flex w-full items-start gap-2.5 px-3 py-2 text-left transition-colors",
                                  active ? "bg-brand-soft/50" : "hover:bg-muted/50",
                                )}
                                onMouseEnter={() => setActiveIndex(flatIdx)}
                                onMouseDown={(e) => e.preventDefault()}
                                onClick={() => goToHit(hit)}
                              >
                                <span className="mt-0.5 flex size-7 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
                                  <Icon size={14} aria-hidden="true" />
                                </span>
                                <div className="min-w-0 flex-1">
                                  <p className="truncate text-[13.5px] font-medium text-foreground">
                                    {hit.title}
                                  </p>
                                  {hit.subtitle ? (
                                    <p className="truncate text-[12px] text-muted-foreground">
                                      {hit.subtitle}
                                    </p>
                                  ) : null}
                                  {hit.status ? (
                                    <span className="mt-1 inline-flex rounded-full border border-border bg-muted px-2 py-0.5 text-[10.5px] font-medium text-muted-foreground">
                                      {hit.status}
                                    </span>
                                  ) : null}
                                </div>
                                <ChevronRight
                                  size={14}
                                  className="mt-1 shrink-0 text-muted-foreground"
                                  aria-hidden="true"
                                />
                              </button>
                            </li>
                          );
                        })}
                      </ul>
                    </div>
                  );
                })}
              </div>
              <div className="border-t border-border px-3 py-2">
                <button
                  type="button"
                  className="flex w-full items-center justify-center gap-1 rounded-lg py-1.5 text-[12.5px] font-semibold text-brand-foreground hover:bg-brand-soft/40"
                  onMouseDown={(e) => e.preventDefault()}
                  onClick={() => goToFullResults(query)}
                >
                  View all results →
                </button>
              </div>
            </>
          ) : null}
        </div>
      ) : null}
    </div>
  );
}

/** Alias matching the requested SearchInput API */
export const SearchInput = GlobalSearch;
