import { useState, useEffect, useRef, useMemo } from "react";
import {
  useListTools,
  useListCategories,
  ListToolsSort,
} from "@workspace/api-client-react";
import { useVirtualizer } from "@tanstack/react-virtual";
import { Layout } from "@/components/layout";
import { ToolCard } from "@/components/tool-card";
import { ToolCardWide } from "@/components/tool-card-wide";
import { ToolRow, TABLE_GRID } from "@/components/tool-row";
import { ViewToggle, type ViewMode } from "@/components/view-toggle";
import { DensityToggle, type Density } from "@/components/density-toggle";
import { useBrowsePreferences, isViewMode, isDensity } from "@/hooks/use-browse-preferences";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Skeleton } from "@/components/ui/skeleton";
import { Search, Wrench, X, ArrowUp, ArrowDown, ArrowUpDown, SlidersHorizontal } from "lucide-react";
import { Link, useLocation, useSearch } from "wouter";
import { cn } from "@/lib/utils";

const SORT_VALUES = new Set<string>(Object.values(ListToolsSort));

const SORT_LABELS: Record<string, string> = {
  [ListToolsSort.newest]: "Newest",
  [ListToolsSort.top_rated]: "Top Rated",
  [ListToolsSort.most_reviewed]: "Most Reviewed",
  [ListToolsSort.name_asc]: "Name (A–Z)",
  [ListToolsSort.name_desc]: "Name (Z–A)",
  [ListToolsSort.recently_updated]: "Recently Updated",
};

function SortHeader({
  active,
  direction,
  onClick,
  children,
  align = "left",
}: {
  active: boolean;
  direction?: "asc" | "desc";
  onClick: () => void;
  children: React.ReactNode;
  align?: "left" | "right";
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={cn(
        "inline-flex items-center gap-1 text-xs font-semibold uppercase tracking-wide hover:text-foreground transition-colors",
        active ? "text-foreground" : "text-muted-foreground",
        align === "right" && "w-full justify-end",
      )}
    >
      {children}
      {active && direction === "asc" ? (
        <ArrowUp className="w-3.5 h-3.5" />
      ) : active && direction === "desc" ? (
        <ArrowDown className="w-3.5 h-3.5" />
      ) : (
        <ArrowUpDown className="w-3.5 h-3.5 opacity-50" />
      )}
    </button>
  );
}

export default function ToolsBrowse() {
  const [, navigate] = useLocation();
  const urlSearch = useSearch();

  const initialParams = useMemo(() => new URLSearchParams(urlSearch), [urlSearch]);
  const initialSearch = initialParams.get("search") ?? "";
  const initialCategory = initialParams.get("category") ?? "all";
  const initialSortParam = initialParams.get("sort") ?? "";
  const initialSort = SORT_VALUES.has(initialSortParam)
    ? (initialSortParam as ListToolsSort)
    : ListToolsSort.newest;

  const { serverView, serverDensity, localView, localDensity, persist } = useBrowsePreferences();

  const [search, setSearch] = useState(initialSearch);
  const [searchInput, setSearchInput] = useState(initialSearch);
  const [category, setCategory] = useState<string>(initialCategory);
  const [sort, setSort] = useState<ListToolsSort>(initialSort);
  const [overrideView, setOverrideView] = useState<ViewMode | null>(null);
  const [overrideDensity, setOverrideDensity] = useState<Density | null>(null);

  const urlView = initialParams.get("view");
  const urlDensity = initialParams.get("density");
  const view: ViewMode =
    (isViewMode(urlView) ? urlView : null) ?? overrideView ?? serverView ?? localView ?? "grid";
  const density: Density =
    (isDensity(urlDensity) ? urlDensity : null) ?? overrideDensity ?? serverDensity ?? localDensity ?? "cozy";

  useEffect(() => {
    const p = new URLSearchParams();
    if (search) p.set("search", search);
    if (category && category !== "all") p.set("category", category);
    if (sort && sort !== ListToolsSort.newest) p.set("sort", sort);
    if (view !== "grid") p.set("view", view);
    if (density !== "cozy") p.set("density", density);
    const qs = p.toString();
    navigate(qs ? `/tools?${qs}` : "/tools", { replace: true });
  }, [search, category, sort, view, density, navigate]);

  useEffect(() => {
    const t = setTimeout(() => setSearch(searchInput), 300);
    return () => clearTimeout(t);
  }, [searchInput]);

  const searchInputRef = useRef<HTMLInputElement>(null);
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement;
      const isTyping =
        target.tagName === "INPUT" ||
        target.tagName === "TEXTAREA" ||
        target.tagName === "SELECT" ||
        target.isContentEditable;
      if (e.key === "/" && !isTyping) {
        e.preventDefault();
        searchInputRef.current?.focus();
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, []);

  const { data: categories, isLoading: loadingCategories } = useListCategories();

  const queryParams = {
    ...(search ? { search } : {}),
    ...(category && category !== "all" ? { category } : {}),
    ...(sort ? { sort } : {}),
  };

  const { data: tools, isLoading: loadingTools } = useListTools(queryParams);
  const allTools = tools ?? [];

  function setView(v: ViewMode) {
    setOverrideView(v);
    persist(v, density);
  }

  function setDensity(d: Density) {
    setOverrideDensity(d);
    persist(view, d);
  }

  const clearFilters = () => {
    setSearch("");
    setSearchInput("");
    setCategory("all");
    setSort(ListToolsSort.newest);
  };

  const hasFilters = search !== "" || category !== "all" || sort !== ListToolsSort.newest;

  function toggleNameSort() {
    setSort(sort === ListToolsSort.name_asc ? ListToolsSort.name_desc : ListToolsSort.name_asc);
  }

  // ---- virtualization ----
  const tableParentRef = useRef<HTMLDivElement>(null);
  const rowsParentRef = useRef<HTMLDivElement>(null);

  const tableVirtualizer = useVirtualizer({
    count: allTools.length,
    getScrollElement: () => tableParentRef.current,
    estimateSize: () => (density === "compact" ? 44 : 64),
    overscan: 8,
  });

  const rowsVirtualizer = useVirtualizer({
    count: allTools.length,
    getScrollElement: () => rowsParentRef.current,
    estimateSize: () => (density === "compact" ? 72 : 116),
    overscan: 4,
  });

  const gridPad = density === "compact" ? "gap-3" : "gap-4";

  const sortActive = (v: ListToolsSort) => sort === v;
  const nameDir: "asc" | "desc" | undefined =
    sort === ListToolsSort.name_asc ? "asc" : sort === ListToolsSort.name_desc ? "desc" : undefined;

  return (
    <Layout>
      <div className="space-y-6 pb-8">
        <div className="flex flex-col sm:flex-row justify-between items-start sm:items-end gap-4">
          <div>
            <h1 className="text-3xl font-bold tracking-tight mb-2">Browse Tools</h1>
            <p className="text-muted-foreground">Discover and evaluate the best tools for your stack.</p>
          </div>
          <Button asChild>
            <Link href="/tools/new">Add a Tool</Link>
          </Button>
        </div>

        {/* Filters */}
        <div className="bg-card border rounded-xl p-4 flex flex-col md:flex-row gap-4">
          <div className="relative flex-1">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
            <Input
              ref={searchInputRef}
              placeholder='Search tools… (press "/" to focus)'
              className="pl-9 w-full"
              value={searchInput}
              onChange={(e) => setSearchInput(e.target.value)}
              data-testid="input-search"
            />
          </div>

          <div className="flex flex-wrap sm:flex-nowrap gap-4 shrink-0">
            <Select value={category} onValueChange={setCategory}>
              <SelectTrigger className="w-full sm:w-[180px]" data-testid="select-category">
                <SelectValue placeholder="All Categories" />
              </SelectTrigger>
              <SelectContent>
                <SelectItem value="all">All Categories</SelectItem>
                {!loadingCategories &&
                  categories?.map((c) => (
                    <SelectItem key={c} value={c}>
                      {c}
                    </SelectItem>
                  ))}
              </SelectContent>
            </Select>

            <Select value={sort} onValueChange={(val) => setSort(val as ListToolsSort)}>
              <SelectTrigger className="w-full sm:w-[180px]" data-testid="select-sort">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                {Object.values(ListToolsSort).map((v) => (
                  <SelectItem key={v} value={v}>
                    {SORT_LABELS[v]}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        {hasFilters && (
          <div className="flex flex-wrap items-center gap-2 -mt-2">
            {search && (
              <Badge variant="secondary" className="gap-1 pl-2.5 pr-1.5 py-1">
                “{search}”
                <button
                  onClick={() => {
                    setSearch("");
                    setSearchInput("");
                  }}
                  className="rounded-sm hover:bg-muted p-0.5"
                  aria-label="Remove search"
                >
                  <X className="w-3.5 h-3.5" />
                </button>
              </Badge>
            )}
            {category !== "all" && (
              <Badge variant="secondary" className="gap-1 pl-2.5 pr-1.5 py-1">
                {category}
                <button
                  onClick={() => setCategory("all")}
                  className="rounded-sm hover:bg-muted p-0.5"
                  aria-label="Remove category"
                >
                  <X className="w-3.5 h-3.5" />
                </button>
              </Badge>
            )}
            {sort !== ListToolsSort.newest && (
              <Badge variant="secondary" className="gap-1 pl-2.5 pr-1.5 py-1">
                {SORT_LABELS[sort]}
                <button
                  onClick={() => setSort(ListToolsSort.newest)}
                  className="rounded-sm hover:bg-muted p-0.5"
                  aria-label="Reset sort"
                >
                  <X className="w-3.5 h-3.5" />
                </button>
              </Badge>
            )}
            <Button variant="link" size="sm" className="px-1 text-muted-foreground" onClick={clearFilters}>
              Clear all
            </Button>
          </div>
        )}

        {/* Results toolbar */}
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="flex items-center text-sm text-muted-foreground">
            <SlidersHorizontal className="w-4 h-4 mr-2" />
            {loadingTools ? "Loading tools…" : `Showing ${allTools.length} tool${allTools.length === 1 ? "" : "s"}`}
          </div>
          <div className="flex items-center gap-3">
            <DensityToggle value={density} onValueChange={setDensity} />
            <ViewToggle value={view} onValueChange={setView} />
          </div>
        </div>

        {/* Results */}
        {loadingTools ? (
          <Skeletons view={view} density={density} />
        ) : allTools.length > 0 ? (
          view === "grid" ? (
            <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", gridPad)}>
              {allTools.map((tool) => (
                <ToolCard key={tool.id} tool={tool} />
              ))}
            </div>
          ) : view === "rows" ? (
            <div ref={rowsParentRef} className="overflow-auto max-h-[72vh]">
              <div className="relative" style={{ height: rowsVirtualizer.getTotalSize() }}>
                {rowsVirtualizer.getVirtualItems().map((vi) => (
                  <div
                    key={allTools[vi.index].id}
                    ref={rowsVirtualizer.measureElement}
                    data-index={vi.index}
                    className="absolute top-0 left-0 w-full"
                    style={{ transform: `translateY(${vi.start}px)` }}
                  >
                    <ToolCardWide tool={allTools[vi.index]} density={density} />
                  </div>
                ))}
              </div>
            </div>
          ) : (
            <div ref={tableParentRef} className="overflow-auto max-h-[72vh] rounded-xl border bg-background">
              <div className={cn("grid items-center gap-3 border-b bg-muted sticky top-0 z-10 px-4", TABLE_GRID)}>
                <div className="py-2.5">
                  <SortHeader active={sortActive(ListToolsSort.name_asc) || sortActive(ListToolsSort.name_desc)} direction={nameDir} onClick={toggleNameSort}>
                    Tool
                  </SortHeader>
                </div>
                <div className="py-2.5 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Category
                </div>
                <div className="py-2.5">
                  <SortHeader active={sortActive(ListToolsSort.top_rated)} onClick={() => setSort(ListToolsSort.top_rated)} align="right">
                    Rating
                  </SortHeader>
                </div>
                <div className="py-2.5">
                  <SortHeader active={sortActive(ListToolsSort.most_reviewed)} onClick={() => setSort(ListToolsSort.most_reviewed)} align="right">
                    Reviews
                  </SortHeader>
                </div>
              </div>
              <div className="relative px-4" style={{ height: tableVirtualizer.getTotalSize() }}>
                {tableVirtualizer.getVirtualItems().map((vi) => {
                  const tool = allTools[vi.index];
                  return (
                    <div
                      key={tool.id}
                      ref={tableVirtualizer.measureElement}
                      data-index={vi.index}
                      className="absolute top-0 left-0 w-full"
                      style={{ transform: `translateY(${vi.start}px)` }}
                    >
                      <ToolRow tool={tool} density={density} />
                    </div>
                  );
                })}
              </div>
            </div>
          )
        ) : (
          <div className="bg-muted/30 border border-dashed rounded-xl py-24 flex flex-col items-center justify-center text-center">
            <div className="bg-muted p-4 rounded-full mb-4">
              <Wrench className="w-8 h-8 text-muted-foreground" />
            </div>
            <h3 className="text-xl font-medium mb-2">No tools found</h3>
            <p className="text-muted-foreground max-w-md mx-auto mb-6">
              We couldn't find any tools matching your current filters. Try adjusting your search criteria or add a
              new tool.
            </p>
            <div className="flex gap-4">
              {hasFilters && (
                <Button variant="outline" onClick={clearFilters}>
                  Clear Filters
                </Button>
              )}
              <Button asChild>
                <Link href="/tools/new">Add Tool</Link>
              </Button>
            </div>
          </div>
        )}
      </div>
    </Layout>
  );
}

function Skeletons({ view, density }: { view: ViewMode; density: Density }) {
  const compact = density === "compact";
  if (view === "grid") {
    return (
      <div className={cn("grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4", compact ? "gap-3" : "gap-4")}>
        {[1, 2, 3, 4, 5, 6, 7, 8].map((i) => (
          <Skeleton key={`sk-grid-${i}`} className="h-[200px] w-full rounded-xl" />
        ))}
      </div>
    );
  }
  if (view === "rows") {
    return (
      <div className={cn("space-y-3")}>
        {[1, 2, 3, 4, 5].map((i) => (
          <Skeleton key={`sk-rows-${i}`} className={cn("w-full rounded-xl", compact ? "h-16" : "h-[104px]")} />
        ))}
      </div>
    );
  }
  return (
    <div className="rounded-xl border overflow-hidden">
      <Skeleton className="h-10 w-full rounded-none" />
      {[1, 2, 3, 4, 5].map((i) => (
        <Skeleton key={`sk-table-${i}`} className={cn("w-full rounded-none border-t border-border/40", compact ? "h-11" : "h-16")} />
      ))}
    </div>
  );
}
