"use client";

/**
 * Full-page search results view for `/app/search`.
 *
 * Reads `?q=<query>` from the URL, runs `searchIndex()` against every
 * SAG store, and renders a filterable result list. Filters apply
 * client-side against the freshly-built index (cheap; the data set is
 * a few thousand items at most).
 *
 * State flow:
 *   - URL `?q=` is the source of truth for the query.
 *   - A local controlled input mirrors it; debounced 250ms before the
 *     URL is updated (via router.replace) so typing doesn't spam history.
 *   - Category-group filter, entity filter, and recent searches live in
 *     React state — the search index itself is recomputed on each render
 *     pass (cheap, deterministic).
 */

import { useEffect, useMemo, useRef, useState } from "react";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { EmptyState } from "@/components/ui/empty-state";
import { Kpi, KpiStrip } from "@/components/ui/kpi";
import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip } from "@/components/ui/tooltip";
import {
  SegmentedControl,
  SegmentedControlItem,
} from "@/components/ui/segmented-control";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { useToast } from "@/components/ui/toast";
import {
  CATEGORY_GROUPS,
  CATEGORY_LABEL,
  RECENT_SEARCHES_KEY,
  buildIndex,
  clearRecentSearches,
  loadRecentSearches,
  recordRecentSearch,
  searchIndex,
  type SearchCategory,
  type SearchCategoryGroup,
  type SearchResult,
} from "@/lib/search";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";

const CATEGORY_TONE: Record<
  SearchCategory,
  "default" | "secondary" | "outline" | "success" | "warning" | "info" | "destructive"
> = {
  entities: "default",
  bills: "info",
  ncdor: "warning",
  "hemp-licenses": "warning",
  "abc-permits": "warning",
  filings: "warning",
  licenses: "warning",
  domains: "secondary",
  employees: "secondary",
  hires: "secondary",
  documents: "outline",
  "social-posts": "outline",
  "music-releases": "outline",
  "music-bookings": "outline",
  subscriptions: "info",
  "owner-draws": "success",
  investments: "success",
  research: "outline",
  "agent-threads": "default",
  activity: "outline",
};

const GROUP_LABEL: Record<SearchCategoryGroup, string> = {
  all: "All",
  records: "Records",
  compliance: "Compliance",
  money: "Money",
  people: "People",
  content: "Content",
  ai: "AI",
};

function formatRelative(iso: string | undefined, nowMs: number): string {
  if (!iso) return "—";
  const t = new Date(iso).getTime();
  if (!Number.isFinite(t)) return "—";
  const diffSec = Math.round((nowMs - t) / 1000);
  if (diffSec < 0) return "soon";
  if (diffSec < 60) return diffSec <= 1 ? "just now" : `${diffSec}s ago`;
  const diffMin = Math.round(diffSec / 60);
  if (diffMin < 60) return `${diffMin}m ago`;
  const diffHr = Math.round(diffMin / 60);
  if (diffHr < 24) return `${diffHr}h ago`;
  const diffDay = Math.round(diffHr / 24);
  if (diffDay < 30) return `${diffDay}d ago`;
  const diffMo = Math.round(diffDay / 30);
  if (diffMo < 12) return `${diffMo}mo ago`;
  const diffYr = Math.round(diffMo / 12);
  return `${diffYr}y ago`;
}

function formatAbsolute(iso: string | undefined): string {
  if (!iso) return "—";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleString("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
    hour: "numeric",
    minute: "2-digit",
  });
}

export function SearchResults() {
  const router = useRouter();
  const params = useSearchParams();
  const urlQuery = params.get("q") ?? "";

  const [loaded, setLoaded] = useState(false);
  const [query, setQuery] = useState(urlQuery);
  const [group, setGroup] = useState<SearchCategoryGroup>("all");
  const [entityFilter, setEntityFilter] = useState<string>("all");
  const [recents, setRecents] = useState<string[]>([]);
  const [nowMs, setNowMs] = useState<number>(() => Date.now());
  const [indexSize, setIndexSize] = useState<number>(0);
  const inputRef = useRef<HTMLInputElement>(null);
  const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastRecordedQuery = useRef<string>("");
  const { toast } = useToast();

  // Initial mount: load recent searches + index size, focus the input,
  // cross-tab listener for recents changes.
  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect -- one-time hydration
    setRecents(loadRecentSearches());
    setIndexSize(buildIndex().length);
    setLoaded(true);
    inputRef.current?.focus();

    function onStorage(e: StorageEvent) {
      if (e.key === RECENT_SEARCHES_KEY) {
        setRecents(loadRecentSearches());
      }
    }
    window.addEventListener("storage", onStorage);
    return () => window.removeEventListener("storage", onStorage);
  }, []);

  // Sync state when URL changes (e.g. back button, deep link from dropdown).
  useEffect(() => {
    // eslint-disable-next-line react-hooks/set-state-in-effect -- mirror URL → local state
    setQuery(urlQuery);
  }, [urlQuery]);

  // Refresh relative timestamps every minute.
  useEffect(() => {
    const id = setInterval(() => setNowMs(Date.now()), 60_000);
    return () => clearInterval(id);
  }, []);

  // Debounced URL sync + recent-search recording.
  useEffect(() => {
    if (!loaded) return;
    if (debounceTimer.current) clearTimeout(debounceTimer.current);
    debounceTimer.current = setTimeout(() => {
      const trimmed = query.trim();
      const targetQuery = trimmed;
      if (targetQuery === urlQuery) return;
      const usp = new URLSearchParams(params.toString());
      if (targetQuery) usp.set("q", targetQuery);
      else usp.delete("q");
      const qs = usp.toString();
      router.replace(qs ? `/app/search?${qs}` : "/app/search");
      if (
        trimmed.length >= 2 &&
        trimmed.toLowerCase() !== lastRecordedQuery.current.toLowerCase()
      ) {
        recordRecentSearch(trimmed);
        lastRecordedQuery.current = trimmed;
        setRecents(loadRecentSearches());
      }
    }, 250);
    return () => {
      if (debounceTimer.current) clearTimeout(debounceTimer.current);
    };
  }, [query, urlQuery, loaded, params, router]);

  const results = useMemo(() => {
    if (!loaded) return [] as SearchResult[];
    return searchIndex(query, {
      group,
      entitySlug: entityFilter === "all" ? undefined : entityFilter,
    });
  }, [query, group, entityFilter, loaded]);

  const categoriesMatched = useMemo(() => {
    const set = new Set<SearchCategory>();
    for (const r of results) set.add(r.category);
    return set.size;
  }, [results]);

  // Entity dropdown — show only orgs that actually have rows in the index,
  // plus "All entities" at the top. Falls back to ALL_ORGANIZATIONS so the
  // user can still narrow even when nothing in the index has the slug yet.
  const entityOptions = useMemo(() => {
    const slugs = new Set<string>();
    for (const r of buildIndex()) {
      if (r.entitySlug) slugs.add(r.entitySlug);
    }
    const candidates = ALL_ORGANIZATIONS.filter((o) => slugs.has(o.slug));
    return candidates.length > 0 ? candidates : ALL_ORGANIZATIONS;
    // The index depends on localStorage state — recompute on every render
    // is cheap and ensures fresh data after a write elsewhere.
  }, []);

  function handleRecentClick(q: string) {
    setQuery(q);
    inputRef.current?.focus();
  }

  function handleClearRecents() {
    clearRecentSearches();
    setRecents([]);
    toast({ title: "Cleared recent searches", variant: "info" });
  }

  const entityFilterLabel =
    entityFilter === "all"
      ? "All entities"
      : (() => {
          const org = ALL_ORGANIZATIONS.find((o) => o.slug === entityFilter);
          return org ? `${org.emoji ?? "🏢"} ${org.name}` : entityFilter;
        })();

  if (!loaded) {
    return (
      <div className="space-y-6">
        <Skeleton className="h-12 w-full" />
        <KpiStrip cols={4}>
          <Skeleton className="h-24" />
          <Skeleton className="h-24" />
          <Skeleton className="h-24" />
          <Skeleton className="h-24" />
        </KpiStrip>
        <Skeleton className="h-12" />
        <Skeleton className="h-64" />
      </div>
    );
  }

  const trimmedQuery = query.trim();
  const showRecents = trimmedQuery.length === 0;

  return (
    <div className="space-y-6">
      {/* Search input */}
      <Card>
        <CardContent className="p-4">
          <div className="flex items-center gap-3">
            <span className="text-lg" aria-hidden="true">
              🔍
            </span>
            <Input
              ref={inputRef}
              type="text"
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              placeholder="Search entities, bills, filings, employees, posts, threads..."
              className="flex-1"
              aria-label="Search SAG Manager"
            />
            {query.length > 0 && (
              <Button
                variant="ghost"
                size="sm"
                onClick={() => {
                  setQuery("");
                  inputRef.current?.focus();
                }}
              >
                Clear
              </Button>
            )}
          </div>
        </CardContent>
      </Card>

      {/* KPI strip */}
      <KpiStrip cols={4}>
        <Kpi
          label="Total results"
          value={String(results.length)}
          tone="brand"
        />
        <Kpi
          label="Categories matched"
          value={String(categoriesMatched)}
          hint={
            categoriesMatched === 0
              ? "Try a broader query"
              : `of ${Object.keys(CATEGORY_LABEL).length} possible`
          }
        />
        <Kpi label="Index size" value={String(indexSize)} hint="rows searched" />
        <Kpi
          label="Recent searches"
          value={String(recents.length)}
          hint={recents.length === 0 ? "No history yet" : "Click below to rerun"}
        />
      </KpiStrip>

      {/* Filter row */}
      <Card>
        <CardContent className="p-4 flex flex-wrap items-center gap-3">
          <SegmentedControl
            value={group}
            onValueChange={(v) => setGroup(v as SearchCategoryGroup)}
            aria-label="Filter by category group"
            className="flex-wrap"
          >
            <SegmentedControlItem value="all">
              {GROUP_LABEL.all}
            </SegmentedControlItem>
            {(Object.keys(CATEGORY_GROUPS) as Array<
              keyof typeof CATEGORY_GROUPS
            >).map((g) => (
              <SegmentedControlItem key={g} value={g}>
                {GROUP_LABEL[g]}
              </SegmentedControlItem>
            ))}
          </SegmentedControl>

          <DropdownMenu>
            <DropdownMenuTrigger>
              <span className="inline-flex h-9 items-center gap-2 rounded-md border border-input bg-background px-3 text-xs font-medium hover:bg-accent">
                Entity: {entityFilterLabel}
                <span aria-hidden="true">▾</span>
              </span>
            </DropdownMenuTrigger>
            <DropdownMenuContent className="max-h-80 overflow-y-auto">
              <DropdownMenuLabel>Filter by entity</DropdownMenuLabel>
              <DropdownMenuItem onSelect={() => setEntityFilter("all")}>
                All entities
              </DropdownMenuItem>
              {entityOptions.length > 0 && <DropdownMenuSeparator />}
              {entityOptions.map((o) => (
                <DropdownMenuItem
                  key={o.slug}
                  onSelect={() => setEntityFilter(o.slug)}
                >
                  <span className="mr-1">{o.emoji ?? "🏢"}</span>
                  {o.name}
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>

          <span className="text-xs text-muted-foreground tabular-nums ml-auto">
            {results.length} of {indexSize}
          </span>
        </CardContent>
      </Card>

      {/* Recent searches (only when query empty) */}
      {showRecents && (
        <Card>
          <CardContent className="p-4">
            <div className="flex items-center justify-between mb-3">
              <h3 className="section-label">Recent searches</h3>
              {recents.length > 0 && (
                <button
                  type="button"
                  onClick={handleClearRecents}
                  className="text-xs text-muted-foreground hover:text-destructive transition-colors"
                >
                  Clear
                </button>
              )}
            </div>
            {recents.length === 0 ? (
              <p className="text-sm text-muted-foreground">
                Searches you run here will appear as quick-rerun chips.
              </p>
            ) : (
              <div className="flex flex-wrap gap-2">
                {recents.map((q) => (
                  <button
                    key={q}
                    type="button"
                    onClick={() => handleRecentClick(q)}
                    className="inline-flex items-center gap-1.5 rounded-full border bg-background px-3 py-1 text-xs hover:bg-accent transition-colors"
                  >
                    <span aria-hidden="true">⟳</span>
                    {q}
                  </button>
                ))}
              </div>
            )}
          </CardContent>
        </Card>
      )}

      {/* Results list */}
      {results.length === 0 ? (
        showRecents ? (
          <EmptyState
            icon="🔍"
            title="Search every corner of SAG Manager"
            description="Start typing to search entities, bills, filings, licenses, employees, social posts, music releases, agent threads, and more. Results update as you type."
          />
        ) : (
          <EmptyState
            icon="🤷"
            title={`No results for "${trimmedQuery}"`}
            description="Try a shorter or differently-worded query, switch the category group, or clear the entity filter."
          />
        )
      ) : (
        <Card>
          <CardContent className="p-0">
            <ul className="divide-y">
              {results.map((r) => {
                const org = r.entitySlug
                  ? ALL_ORGANIZATIONS.find((o) => o.slug === r.entitySlug)
                  : undefined;
                return (
                  <li key={`${r.category}-${r.id}`}>
                    <Link
                      href={r.href}
                      className="flex items-start gap-3 px-4 py-3 hover:bg-accent/40 transition-colors"
                    >
                      <Badge
                        variant={CATEGORY_TONE[r.category]}
                        className="text-[10px] shrink-0 mt-0.5"
                      >
                        {CATEGORY_LABEL[r.category]}
                      </Badge>
                      <div className="min-w-0 flex-1">
                        <div className="font-medium truncate text-sm">
                          {r.title}
                        </div>
                        {r.subtitle && (
                          <div className="text-xs text-muted-foreground truncate mt-0.5">
                            {r.subtitle}
                          </div>
                        )}
                      </div>
                      {org && (
                        <span className="text-xs text-muted-foreground shrink-0 hidden md:inline-flex items-center gap-1 max-w-[160px] truncate">
                          <span aria-hidden="true">{org.emoji ?? "🏢"}</span>
                          <span className="truncate">{org.name}</span>
                        </span>
                      )}
                      {r.updatedAt && (
                        <Tooltip content={formatAbsolute(r.updatedAt)}>
                          <span className="text-xs text-muted-foreground tabular-nums shrink-0">
                            {formatRelative(r.updatedAt, nowMs)}
                          </span>
                        </Tooltip>
                      )}
                    </Link>
                  </li>
                );
              })}
            </ul>
          </CardContent>
        </Card>
      )}

      <p className="text-xs text-muted-foreground">
        Search runs locally against everything in this browser. Recents stored
        at <code className="font-mono">{RECENT_SEARCHES_KEY}</code>. Results are
        capped at 200.
      </p>
    </div>
  );
}
