"use client";
import { useMemo, useState } from "react";
import { Search, X, CheckSquare, RectangleVertical, RectangleHorizontal } from "lucide-react";
import { ActressCard, type ActressCardData } from "./ActressCard";
import { CategoryIcon } from "./CategoryIcon";
import { ActressSelectionProvider, useActressSelection } from "./ActressSelectionProvider";
import { ActressBulkBar } from "./ActressBulkBar";
import { reverseName } from "@/lib/jav/nameUtils";
import type { ActressCategory } from "@/lib/db/queries";
import { cn } from "@/lib/utils";

const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const NON_LATIN = "#";

function bucketFor(name: string): string {
  const c = name.trim().slice(0, 1).toUpperCase();
  return c >= "A" && c <= "Z" ? c : NON_LATIN;
}

interface ActressFull extends ActressCardData {
  altNames?: string | null;
}

export function ActressDirectory(props: { items: ActressFull[]; categories: ActressCategory[] }) {
  return (
    <ActressSelectionProvider>
      <DirectoryInner {...props} />
    </ActressSelectionProvider>
  );
}

function DirectoryInner({
  items,
  categories,
}: {
  items: ActressFull[];
  categories: ActressCategory[];
}) {
  const sel = useActressSelection();
  const [query, setQuery] = useState("");
  const [activeLetter, setActiveLetter] = useState<string | null>(null);
  // null = ALL, "unassigned" = actresses with no categories, number = category id
  const [activeCategoryId, setActiveCategoryId] = useState<number | "unassigned" | null>(null);
  // P (default) uses portraits.p1, L uses portraits.ph (golden landscape).
  const [view, setView] = useState<"portrait" | "landscape">("portrait");

  const builtins = useMemo(() => ({
    favoriteId: categories.find((c) => c.slug === "favorite")?.id,
    vipId: categories.find((c) => c.slug === "vip")?.id,
  }), [categories]);

  const enriched = useMemo(() => items.map((a) => {
    const reversed = reverseName(a.name);
    const altParts = (a.altNames ?? "").split(/[,、，]/).map((s) => s.trim()).filter(Boolean);
    const haystack = [a.name, reversed ?? "", ...altParts].join(" ").toLowerCase();
    return { actress: a, haystack, bucket: bucketFor(a.name) };
  }), [items]);

  const tokens = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
  const searched = tokens.length === 0
    ? enriched
    : enriched.filter(({ haystack }) => tokens.every((t) => haystack.includes(t)));

  const categoryFiltered = activeCategoryId == null
    ? searched
    : activeCategoryId === "unassigned"
    ? searched.filter(({ actress }) => actress.categories.length === 0)
    : searched.filter(({ actress }) => actress.categories.some((c) => c.id === activeCategoryId));

  const unassignedCount = useMemo(
    () => searched.reduce((n, e) => (e.actress.categories.length === 0 ? n + 1 : n), 0),
    [searched],
  );

  // Pill display order: ALL · VIP · Favorite · Not Assigned · everything
  // else. VIP and Favorite are seeded built-ins identified by slug; if
  // they're absent for any reason we just skip them.
  const orderedCategories = useMemo(() => {
    const vip = categories.find((c) => c.slug === "vip");
    const fav = categories.find((c) => c.slug === "favorite");
    const rest = categories.filter((c) => c.slug !== "favorite" && c.slug !== "vip");
    return [...(vip ? [vip] : []), ...(fav ? [fav] : []), ...rest];
  }, [categories]);

  const counts = useMemo(() => {
    const m: Record<string, number> = {};
    for (const e of categoryFiltered) m[e.bucket] = (m[e.bucket] ?? 0) + 1;
    return m;
  }, [categoryFiltered]);

  const categoryCounts = useMemo(() => {
    const m: Record<number, number> = {};
    for (const e of searched) {
      for (const c of e.actress.categories) m[c.id] = (m[c.id] ?? 0) + 1;
    }
    return m;
  }, [searched]);

  const visible = activeLetter
    ? categoryFiltered.filter((e) => e.bucket === activeLetter)
    : categoryFiltered;

  const grouped = useMemo(() => {
    const groups: Record<string, ActressFull[]> = {};
    for (const { actress, bucket } of visible) {
      (groups[bucket] ??= []).push(actress);
    }
    for (const k of Object.keys(groups)) {
      groups[k].sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
    }
    return groups;
  }, [visible]);

  const orderedBuckets = [...LETTERS, NON_LATIN].filter((b) => (grouped[b]?.length ?? 0) > 0);

  // Visible IDs in the exact rendered order — used for shift-click range and "select all visible".
  const orderedIds = useMemo(() => {
    const out: number[] = [];
    for (const b of orderedBuckets) for (const a of grouped[b]) out.push(a.id);
    return out;
  }, [orderedBuckets, grouped]);

  const allVisibleSelected = orderedIds.length > 0 && orderedIds.every((id) => sel.has(id));

  const renderCategoryPill = (c: ActressCategory) => {
    const n = categoryCounts[c.id] ?? 0;
    const enabled = n > 0;
    const active = activeCategoryId === c.id;
    const color = c.color ?? "var(--color-cyan)";
    return (
      <button
        key={c.id}
        type="button"
        disabled={!enabled}
        onClick={() => setActiveCategoryId(active ? null : c.id)}
        className={`flex items-center justify-center gap-1.5 text-xs font-mono font-medium px-3 py-1.5 rounded-full border transition-colors min-w-[140px] ${
          active
            ? "border-transparent"
            : enabled
            ? "glass glass-hover"
            : "text-[var(--color-fg-muted)]/40 cursor-not-allowed"
        }`}
        style={active ? { background: color, color: "#000" } : undefined}
      >
        <CategoryIcon name={c.icon} className="w-3 h-3" />
        {c.name}
        {enabled && (
          <span className={`tabular-nums ${active ? "text-black/70" : "text-[var(--color-fg-muted)]"}`}>{n}</span>
        )}
      </button>
    );
  };

  return (
    <div>
      <div className="flex flex-col sm:flex-row sm:items-center gap-3 mb-4">
        <div className="relative flex-1">
          <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-[var(--color-fg-muted)] pointer-events-none" />
          <input
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Filter Cast — Name, Reversed, Alt Names…"
            className="w-full glass rounded-lg pl-9 pr-9 py-2 text-sm outline-none focus:border-[var(--color-cyan)]"
          />
          {query && (
            <button
              type="button"
              onClick={() => setQuery("")}
              className="absolute right-2 top-1/2 -translate-y-1/2 text-[var(--color-fg-muted)] hover:text-[var(--color-fg)]"
              aria-label="Clear filter"
            >
              <X className="w-4 h-4" />
            </button>
          )}
        </div>
        <button
          type="button"
          onClick={() => allVisibleSelected ? sel.clear() : sel.selectMany(orderedIds)}
          disabled={orderedIds.length === 0}
          className={`flex items-center justify-center gap-1.5 text-xs px-3 py-2 rounded-lg transition-colors disabled:opacity-40 w-[180px] ${
            allVisibleSelected ? "bg-[var(--color-cyan)] text-black font-medium" : "glass glass-hover"
          }`}
        >
          <CheckSquare className="w-3.5 h-3.5" />
          {allVisibleSelected ? "Deselect All Visible" : "Select All Visible"}
          {orderedIds.length > 0 && (
            <span className={`tabular-nums ${allVisibleSelected ? "text-black/70" : "text-[var(--color-fg-muted)]"}`}>
              {orderedIds.length}
            </span>
          )}
        </button>
      </div>

      {categories.length > 0 && (
        <div className="flex items-start gap-1.5">
          <div className="flex flex-wrap items-center gap-1.5 flex-1 min-w-0">
          <button
            type="button"
            onClick={() => setActiveCategoryId(null)}
            className={`text-xs font-mono font-medium px-3 py-1.5 rounded-full border transition-colors ${
              activeCategoryId === null ? "bg-[var(--color-cyan)] text-black border-transparent" : "glass glass-hover"
            }`}
          >
            ALL
            <span className={`ml-1.5 tabular-nums ${activeCategoryId === null ? "text-black/70" : "text-[var(--color-fg-muted)]"}`}>
              {searched.length}
            </span>
          </button>
          {orderedCategories
            .filter((c) => c.slug === "favorite" || c.slug === "vip")
            .map((c) => renderCategoryPill(c))}
          <button
            type="button"
            disabled={unassignedCount === 0}
            onClick={() => setActiveCategoryId(activeCategoryId === "unassigned" ? null : "unassigned")}
            className={`flex items-center justify-center text-xs font-mono font-medium px-3 py-1.5 rounded-full border transition-colors min-w-[140px] ${
              activeCategoryId === "unassigned"
                ? "bg-[var(--color-coral)] text-black border-transparent"
                : unassignedCount > 0
                ? "glass glass-hover"
                : "text-[var(--color-fg-muted)]/40 cursor-not-allowed"
            }`}
            title="Actresses with no category assigned"
          >
            Not Assigned
            <span className={`ml-1.5 tabular-nums ${activeCategoryId === "unassigned" ? "text-black/70" : "text-[var(--color-fg-muted)]"}`}>
              {unassignedCount}
            </span>
          </button>
          {orderedCategories
            .filter((c) => c.slug !== "favorite" && c.slug !== "vip")
            .map((c) => {
              return renderCategoryPill(c);
          })}
          </div>
          <div className="shrink-0 flex justify-end items-center gap-2">
            <ActressBulkBar categories={categories} />
            <div className="flex items-center rounded-lg glass overflow-hidden text-xs">
              <button
                type="button"
                onClick={() => setView("portrait")}
                className={cn(
                  "flex items-center gap-1 px-2.5 py-1.5",
                  view === "portrait"
                    ? "bg-[var(--color-cyan)] text-black font-medium"
                    : "text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
                )}
                title="Portrait view (default — uses P1 portrait slot)"
              >
                <RectangleVertical className="w-3.5 h-3.5" /> P
              </button>
              <button
                type="button"
                onClick={() => setView("landscape")}
                className={cn(
                  "flex items-center gap-1 px-2.5 py-1.5",
                  view === "landscape"
                    ? "bg-[var(--color-cyan)] text-black font-medium"
                    : "text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]",
                )}
                title="Landscape view (uses L portrait slot)"
              >
                <RectangleHorizontal className="w-3.5 h-3.5" /> L
              </button>
            </div>
          </div>
        </div>
      )}

      <div className="flex items-stretch gap-1 mt-4 mb-4 w-full">
        <button
          type="button"
          onClick={() => setActiveLetter(null)}
          className={`flex-1 flex flex-col items-center justify-center font-mono py-2 rounded-lg border transition-colors ${
            activeLetter === null ? "bg-[var(--color-cyan)] text-black border-transparent" : "glass glass-hover"
          }`}
        >
          <span className="text-base font-semibold leading-none">ALL</span>
          <span className={`text-[10px] font-semibold tabular-nums mt-0.5 ${activeLetter === null ? "text-black/70" : "text-[var(--color-fg-muted)]"}`}>
            {categoryFiltered.length}
          </span>
        </button>
        {[...LETTERS, NON_LATIN].map((L) => {
          const n = counts[L] ?? 0;
          const enabled = n > 0;
          const active = activeLetter === L;
          return (
            <button
              key={L}
              type="button"
              disabled={!enabled}
              onClick={() => setActiveLetter(active ? null : L)}
              className={`flex-1 flex flex-col items-center justify-center font-mono py-2 rounded-lg border transition-colors ${
                active
                  ? "bg-[var(--color-cyan)] text-black border-transparent"
                  : enabled
                  ? "glass glass-hover"
                  : "border-transparent text-[var(--color-fg-muted)]/40 cursor-not-allowed"
              }`}
            >
              <span className="text-base font-semibold leading-none">{L}</span>
              <span className={`text-[10px] font-semibold tabular-nums mt-0.5 ${
                active ? "text-black/70" : enabled ? "text-[var(--color-fg-muted)]" : "text-transparent"
              }`}>
                {enabled ? n : 0}
              </span>
            </button>
          );
        })}
      </div>

      {orderedBuckets.length === 0 && (
        <div className="glass rounded-2xl p-card text-center text-[var(--color-fg-dim)] text-sm">
          No matches.
        </div>
      )}

      {activeLetter === null ? (
        <div key={view} className={"fade-in " + (view === "landscape"
  ? "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4"
  : "flex flex-wrap gap-4")}>
          {orderedBuckets.flatMap((b) => grouped[b]).map((a) => (
            <ActressCard key={a.id} actress={a} builtins={builtins} orderedIds={orderedIds} view={view} />
          ))}
        </div>
      ) : (
        <div key={view} className="fade-in space-y-8">
          {orderedBuckets.map((b) => (
            <section key={b} id={`letter-${b}`} className="scroll-mt-20">
              <h2 className="text-sm font-mono uppercase tracking-wider text-[var(--color-fg-muted)] mb-3">
                {b}
                <span className="ml-2 text-[var(--color-fg-dim)] tabular-nums">{grouped[b].length}</span>
              </h2>
              <div className={view === "landscape"
  ? "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 xl:grid-cols-4 gap-4"
  : "flex flex-wrap gap-4"}>
                {grouped[b].map((a) => (
                  <ActressCard key={a.id} actress={a} builtins={builtins} orderedIds={orderedIds} view={view} />
                ))}
              </div>
            </section>
          ))}
        </div>
      )}
    </div>
  );
}
