import { useCallback, useEffect, useMemo, useState } from "react";
import { useNavigate, useRouterState } from "@tanstack/react-router";
import {
  Activity,
  Building2,
  ChevronRight,
  FileText,
  HelpCircle,
  Loader2,
  Search,
  Truck,
} from "lucide-react";
import type { AuthPlatform } from "@/lib/auth";
import { getSession } from "@/lib/auth";
import {
  categoryLabel,
  CLIENT_SEARCH_FILTERS,
  FIRM_SEARCH_FILTERS,
  searchApi,
  searchNavigation,
  type SearchCategory,
  type SearchHit,
} from "@/lib/search-api";
import { GlobalSearch } from "@/components/search/GlobalSearch";
import { EmptyState, PageHeader, SectionCard } from "@/components/ledger/Primitives";
import { cn } from "@/lib/utils";

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;
  }
}

export function SearchPage({ platform }: { platform: AuthPlatform }) {
  const navigate = useNavigate();
  const searchStr = useRouterState({ select: (s) => s.location.searchStr });
  const initialQ = useMemo(() => {
    const params = new URLSearchParams(searchStr);
    return params.get("q") ?? "";
  }, [searchStr]);

  const session = getSession(platform);
  const filters = platform === "firm" ? FIRM_SEARCH_FILTERS : CLIENT_SEARCH_FILTERS;
  const [filter, setFilter] = useState<SearchCategory | "all">("all");
  const [query, setQuery] = useState(initialQ);
  const [loading, setLoading] = useState(false);
  const [items, setItems] = useState<SearchHit[]>([]);
  const [total, setTotal] = useState(0);

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

  const commitQuery = useCallback(
    (q: string) => {
      setQuery(q);
      void navigate({
        to: "/search",
        search: q.trim() ? ({ q: q.trim() } as never) : ({} as never),
        replace: true,
      });
    },
    [navigate],
  );

  useEffect(() => {
    if (!session?.email || !query.trim()) {
      setItems([]);
      setTotal(0);
      return;
    }
    const controller = new AbortController();
    setLoading(true);
    void searchApi(platform, session.email, query.trim(), {
      mode: "full",
      category: filter,
      limit: 60,
      clientId: session.clientId,
      signal: controller.signal,
    })
      .then((res) => {
        setItems(res.items);
        setTotal(res.total);
      })
      .catch((err) => {
        if ((err as Error).name === "AbortError") return;
        setItems([]);
        setTotal(0);
      })
      .finally(() => setLoading(false));
    return () => controller.abort();
  }, [platform, session?.email, session?.clientId, query, filter]);

  const grouped = useMemo(() => {
    const map: Partial<Record<SearchCategory, SearchHit[]>> = {};
    for (const hit of items) {
      (map[hit.category] ??= []).push(hit);
    }
    return map;
  }, [items]);

  const order: SearchCategory[] =
    platform === "firm"
      ? ["clients", "documents", "suppliers", "questions", "activity"]
      : ["documents", "questions", "activity"];

  const openHit = (hit: SearchHit) => {
    const nav = searchNavigation(platform, hit);
    void navigate({
      to: nav.to as never,
      params: nav.params as never,
      search: nav.search as never,
    });
  };

  return (
    <div className="space-y-6">
      <PageHeader
        eyebrow={platform === "firm" ? "Firm" : "Client"}
        title={platform === "firm" ? "Search" : "Search your documents"}
        subtitle={
          query.trim()
            ? `Search results for “${query.trim()}”`
            : platform === "firm"
              ? "Find clients, invoices, suppliers, questions and activity."
              : "Find your invoices, questions and recent updates."
        }
      />

      <GlobalSearch
        platform={platform}
        variant="page"
        initialQuery={query}
        onQueryCommit={commitQuery}
      />

      {query.trim() ? (
        <>
          <div className="flex flex-wrap items-center justify-between gap-3">
            <p className="text-[13.5px] text-muted-foreground">
              {loading ? "Searching…" : `${total} result${total === 1 ? "" : "s"}`}
            </p>
            <div className="flex flex-wrap gap-1.5">
              {filters.map((f) => (
                <button
                  key={f.key}
                  type="button"
                  onClick={() => setFilter(f.key)}
                  className={cn(
                    "rounded-full px-3 py-1.5 text-[12px] font-medium transition-colors",
                    filter === f.key
                      ? "bg-primary text-primary-foreground"
                      : "bg-muted text-muted-foreground hover:text-foreground",
                  )}
                >
                  {f.label}
                </button>
              ))}
            </div>
          </div>

          {loading ? (
            <SectionCard>
              <div className="flex items-center justify-center gap-2 px-5 py-12 text-[13.5px] text-muted-foreground">
                <Loader2 size={16} className="animate-spin" />
                Searching…
              </div>
            </SectionCard>
          ) : items.length === 0 ? (
            <SectionCard>
              <EmptyState
                icon={Search}
                title="No results found"
                description={
                  platform === "firm"
                    ? `We couldn’t find anything matching “${query.trim()}”. Try searching for a client, invoice, document, supplier, or question.`
                    : `Try searching by supplier name, invoice number, or filename.`
                }
              />
            </SectionCard>
          ) : filter === "all" ? (
            <div className="space-y-4">
              {order.map((cat) => {
                const group = grouped[cat];
                if (!group?.length) return null;
                return (
                  <SectionCard key={cat} title={categoryLabel(cat)}>
                    <ResultList items={group} onOpen={openHit} />
                  </SectionCard>
                );
              })}
            </div>
          ) : (
            <SectionCard title={categoryLabel(filter)}>
              <ResultList items={items} onOpen={openHit} />
            </SectionCard>
          )}
        </>
      ) : (
        <SectionCard>
          <EmptyState
            icon={Search}
            title="Start typing to search"
            description={
              platform === "firm"
                ? "Search clients, invoices, documents, suppliers, questions and activity."
                : "Search your documents, questions and activity."
            }
          />
        </SectionCard>
      )}
    </div>
  );
}

function ResultList({
  items,
  onOpen,
}: {
  items: SearchHit[];
  onOpen: (hit: SearchHit) => void;
}) {
  return (
    <ul className="divide-y divide-border">
      {items.map((hit) => {
        const Icon = iconFor(hit.category);
        return (
          <li key={hit.id}>
            <button
              type="button"
              onClick={() => onOpen(hit)}
              className="flex w-full items-start gap-3 px-5 py-3.5 text-left transition-colors hover:bg-brand-soft/40"
            >
              <span className="mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg bg-muted text-muted-foreground">
                <Icon size={16} aria-hidden="true" />
              </span>
              <div className="min-w-0 flex-1">
                <p className="truncate text-[14px] font-medium text-foreground">{hit.title}</p>
                {hit.subtitle ? (
                  <p className="mt-0.5 truncate text-[12.5px] text-muted-foreground">{hit.subtitle}</p>
                ) : null}
                {hit.meta ? (
                  <p className="mt-0.5 truncate text-[12px] text-muted-foreground/90">{hit.meta}</p>
                ) : null}
                {hit.status ? (
                  <span className="mt-1.5 inline-flex rounded-full border border-border bg-muted px-2.5 py-0.5 text-[11px] font-medium text-muted-foreground">
                    {hit.status}
                  </span>
                ) : null}
              </div>
              <ChevronRight size={16} className="mt-1 text-muted-foreground" aria-hidden="true" />
            </button>
          </li>
        );
      })}
    </ul>
  );
}
