/**
 * PartsBrowseClient
 * -----------------------------------------------------------------------------
 * Browse shell for parts listing pages.
 * Owns:
 * - fetching parts from backend
 * - filter + sort + pagination state
 * - layout + list/card views
 */

"use client";

import Link from "next/link";
import { useEffect, useMemo, useState } from "react";
import { usePathname, useRouter, useSearchParams } from "next/navigation";

import Filters from "@/components/parts/Filters";
import SortBar from "@/components/parts/SortBar";
import PartsGrid from "@/components/parts/PartsGrid";
import Pagination from "@/components/parts/Pagination";
import PlatformSwitcher from "@/components/parts/PlatformSwitcher";
import { normalizePlatformKey } from "@/lib/platforms";
import type { UiPart } from "@/types/uiPart";
import type { BuilderSlotKey, Category } from "@/types/builderSlots";
import {
  PART_ROLE_TO_CATEGORY,
  normalizePartRole,
} from "@/lib/catalogMappings";

type PageResponse<T> = {
  content: T[];
  totalElements: number;
  totalPages: number;
  number: number; // 0-based
  size: number;
};

function unwrapContent<T>(json: any): { items: T[]; page?: PageResponse<T> } {
  if (!json) return { items: [] };
  if (Array.isArray(json)) return { items: json };
  if (Array.isArray(json.content))
    return { items: json.content, page: json as PageResponse<T> };
  return { items: [] };
}

type ViewMode = "card" | "list";
type SortOption = "relevance" | "price-asc" | "price-desc" | "brand-asc";

type GunbuilderProductFromApi = {
  id: string | number;
  name: string;
  brand: string;
  platform: string;
  partRole: string;
  price: number | null;
  imageUrl: string | null;
  buyUrl: string | null;
  inStock?: boolean | null;
};

const API_BASE_URL =
  process.env.NEXT_PUBLIC_API_BASE_URL ?? "http://localhost:8080";

const PAGE_SIZE = 24;

function normalizeId(id: string | number) {
  return typeof id === "number" ? String(id) : id;
}

function toSlug(s: string) {
  return (s ?? "")
    .toLowerCase()
    .replaceAll(/[^a-z0-9]+/g, "-")
    .replaceAll(/(^-|-$)/g, "")
    .trim();
}

/**
 * Canonical product details route:
 * /parts/p/[platform]/[partRole]/[productSlug]
 */
function buildDetailHref(platform: string, partRole: string, p: UiPart) {
  const slug = toSlug(`${p.brand ?? ""} ${p.name ?? ""}`);
  return `/parts/p/${encodeURIComponent(platform)}/${encodeURIComponent(
    partRole
  )}/${encodeURIComponent(`${p.id}-${slug}`)}`;
}

export default function PartsBrowseClient(props: {
  partRole: string;
  platform?: string | null; // if null, read from query param or default
  title?: string;
  subtitle?: string;
}) {
  const router = useRouter();
  const searchParams = useSearchParams();
  const pathname = usePathname();

  // ✅ Builder-mode = /parts/p/... (detail routes)
  const isBuilderMode = pathname.startsWith("/parts/p/");

  // ✅ Respect prop override first, else read query, else fallback
  const effectivePlatform = normalizePlatformKey(
    props.platform ?? searchParams.get("platform") ?? "AR15"
  );

  const partRole = props.partRole;

  const [viewMode, setViewMode] = useState<ViewMode>("list");
  const [parts, setParts] = useState<UiPart[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  const [brandFilter, setBrandFilter] = useState<string[]>([]);
  const [caliberFilter, setCaliberFilter] = useState<string[]>([]);
  const [sortBy, setSortBy] = useState<SortOption>("relevance");
  const [searchQuery, setSearchQuery] = useState("");
  const [priceRange, setPriceRange] = useState<{
    min: number | null;
    max: number | null;
  }>({
    min: null,
    max: null,
  });
  const [inStockOnly, setInStockOnly] = useState(false);
  const [currentPage, setCurrentPage] = useState(1); // UI 1-based
  const [serverTotalPages, setServerTotalPages] = useState(1);
  const [serverTotalElements, setServerTotalElements] = useState(0);
  // ----------------------------
  // Fetch parts
  // ----------------------------
  useEffect(() => {
    if (!partRole) return;

    const controller = new AbortController();

    async function fetchParts() {
      try {
        setLoading(true);
        setError(null);

        const search = new URLSearchParams();
        search.set("platform", normalizePlatformKey(effectivePlatform));
        search.append("partRole", partRole);

        // server paging (0-based)
        search.set("page", String(currentPage - 1));
        search.set("size", String(PAGE_SIZE));

        // optional server search + sort (backend can ignore for now)
        if (searchQuery.trim()) search.set("q", searchQuery.trim());
        if (brandFilter.length)
          brandFilter.forEach((b) => search.append("brand", b));

        // server search caliber
        if (caliberFilter.length)
          caliberFilter.forEach((c) => search.append("caliber", c));

        // sort mapping (Spring-style: sort=field,dir)
        switch (sortBy) {
          case "price-asc":
            search.set("sort", "price,asc");
            break;
          case "price-desc":
            search.set("sort", "price,desc");
            break;
          case "brand-asc":
            search.set("sort", "brand,asc");
            break;
          case "relevance":
          default:
            // fallback (or whatever you consider "relevance")
            search.set("sort", "updatedAt,desc");
            break;
        }

        const res = await fetch(
          `${API_BASE_URL}/api/v1/catalog/options?${search.toString()}`,
          {
            signal: controller.signal,
          }
        );

        if (!res.ok) throw new Error(`Failed to load products (${res.status})`);

        const json = await res.json();
        const { items, page } = unwrapContent<GunbuilderProductFromApi>(json);

        setParts(
          items.map((p) => ({
            id: normalizeId(p.id),
            name: p.name,
            brand: p.brand,
            platform: p.platform,
            partRole: p.partRole,
            price: p.price,
            imageUrl: p.imageUrl ?? undefined,
            buyUrl: p.buyUrl ?? undefined,
            inStock: p.inStock ?? undefined,
            caliber: (p as any).caliber ?? null,
          }))
        );

        if (page) {
          setServerTotalPages(page.totalPages ?? 1);
          setServerTotalElements(page.totalElements ?? items.length);
        } else {
          // backward compat
          setServerTotalPages(1);
          setServerTotalElements(items.length);
        }
      } catch (err: any) {
        if (err?.name === "AbortError") return;
        setError(err?.message ?? "Failed to load products");
      } finally {
        setLoading(false);
      }
    }

    fetchParts();
    return () => controller.abort();
  }, [
    partRole,
    effectivePlatform,
    currentPage,
    searchQuery,
    sortBy,
    brandFilter,
    caliberFilter,
  ]);
  // Reset pagination on filters
  useEffect(() => {
    setCurrentPage(1);
  }, [
    partRole,
    effectivePlatform,
    brandFilter,
    caliberFilter,
    sortBy,
    searchQuery,
    priceRange,
    inStockOnly,
  ]);

  // Reset scroll on route change
  useEffect(() => {
    window.scrollTo({ top: 0, behavior: "auto" });
  }, [pathname]);

  // ----------------------------
  // Derived values
  // ----------------------------
  const availableBrands = useMemo(
    () =>
      Array.from(new Set(parts.map((p) => p.brand)))
        .filter(Boolean)
        .sort((a, b) => a.localeCompare(b)),
    [parts]
  );

  const availableCalibers = useMemo(
    () =>
      Array.from(new Set(parts.map((p: any) => p.caliber)))
        .filter(Boolean)
        .sort((a, b) => String(a).localeCompare(String(b))),
    [parts]
  );

  const priceBounds = useMemo(() => {
    const prices = parts
      .map((p) => p.price)
      .filter((v): v is number => typeof v === "number");
    if (!prices.length) return { min: null, max: null };
    return { min: Math.min(...prices), max: Math.max(...prices) };
  }, [parts]);

  // Keep priceRange clamped to bounds when bounds change
  useEffect(() => {
    const minBound = priceBounds.min;
    const maxBound = priceBounds.max;
    if (minBound == null || maxBound == null) return;

    setPriceRange((prev) => {
      const nextMin =
        prev.min == null ? minBound : Math.max(minBound, prev.min);
      const nextMax =
        prev.max == null ? maxBound : Math.min(maxBound, prev.max);

      // Ensure min never exceeds max (in case user typed weird values)
      return {
        min: Math.min(nextMin, nextMax),
        max: Math.max(nextMin, nextMax),
      };
    });
  }, [priceBounds.min, priceBounds.max]);

  const filteredParts = useMemo(() => parts, [parts]);
  const totalPages = Math.max(1, serverTotalPages);
  const paginatedParts = filteredParts; // filteredParts should become just parts now (see below)

  const visibleRange = {
    start: serverTotalElements ? (currentPage - 1) * PAGE_SIZE + 1 : 0,
    end: Math.min(currentPage * PAGE_SIZE, serverTotalElements),
  };

  const headingTitle = props.title ?? `${partRole.replaceAll("-", " ")} parts`;
  const headingSubtitle = props.subtitle ?? "Browse available parts.";

  // ----------------------------
  // Add → Builder handoff
  // ----------------------------
  const handleAddToBuild = (p: UiPart) => {
    // Always normalize first; our mappings may alias multiple roles to one canonical builder category
    const roleKey = normalizePartRole(partRole);

    const categoryId: BuilderSlotKey | null =
      PART_ROLE_TO_CATEGORY[roleKey] ??
      PART_ROLE_TO_CATEGORY[partRole] ??
      null;

    if (!categoryId) {
      alert(
        `No Category mapping found for role "${partRole}" (normalized: "${roleKey}"). Add it to catalogMappings.`
      );
      return;
    }

    const qp = new URLSearchParams();
    qp.set("platform", normalizePlatformKey(effectivePlatform));
    qp.set("select", `${categoryId}:${p.id}`);

    router.push(`/builder?${qp.toString()}`);
  };

  return (
    <main className="min-h-screen bg-black text-zinc-50">
      <div className="mx-auto max-w-6xl px-4 py-6 lg:py-10">
        <header className="mb-6 flex justify-between gap-4">
          <div>
            <p className="text-xs font-semibold tracking-[0.2em] uppercase text-zinc-500">
              Battl Builders
            </p>

            <h1 className="mt-1 text-2xl md:text-3xl font-semibold">
              {headingTitle}{" "}
              <span className="text-amber-300">{effectivePlatform}</span>
            </h1>

            <p className="mt-2 text-sm text-zinc-400 max-w-xl">
              {headingSubtitle}
            </p>

            {/* {!isBuilderMode && (
              <div className="mt-4 flex flex-wrap items-center gap-3">
                <PlatformSwitcher
                  currentPlatform={effectivePlatform}
                  partRole={partRole}
                  preserveQuery
                  mode="browse"
                /> */}

            <Link
              href={`/builder?platform=${encodeURIComponent(
                effectivePlatform
              )}`}
              className="inline-flex items-center rounded-md bg-amber-400 px-3 py-2 text-xs font-semibold text-black hover:bg-amber-300 transition-colors"
            >
              Start New Build →
            </Link>
            {/* </div>
            )} */}
          </div>

          {isBuilderMode && (
            <div className="flex items-center gap-2">
              <Link
                href={`/builder?platform=${encodeURIComponent(
                  effectivePlatform
                )}`}
                className="rounded-md border border-zinc-700 bg-zinc-900/70 px-3 py-2 text-xs font-semibold hover:bg-zinc-800"
              >
                ← Back to Build
              </Link>

              {/* Optional: view toggle in builder-mode too */}
              {parts.length > 0 && (
                <div className="flex gap-2 border border-zinc-800 rounded-md p-1 bg-zinc-950/60">
                  <button
                    type="button"
                    onClick={() => setViewMode("card")}
                    className={`px-3 py-1.5 text-xs font-medium rounded transition-colors ${
                      viewMode === "card"
                        ? "bg-zinc-800 text-zinc-50"
                        : "text-zinc-400 hover:text-zinc-300"
                    }`}
                  >
                    Card
                  </button>
                  <button
                    type="button"
                    onClick={() => setViewMode("list")}
                    className={`px-3 py-1.5 text-xs font-medium rounded transition-colors ${
                      viewMode === "list"
                        ? "bg-zinc-800 text-zinc-50"
                        : "text-zinc-400 hover:text-zinc-300"
                    }`}
                  >
                    List
                  </button>
                </div>
              )}
            </div>
          )}
        </header>

        <section className="rounded-lg border border-zinc-800 bg-zinc-950/60 p-4">
          <div className="flex flex-col md:flex-row gap-4">
            {parts.length > 0 && (
              <aside className="w-full md:w-64">
                <Filters
                  partRoleLabel={partRole}
                  availableBrands={availableBrands}
                  brandFilter={brandFilter}
                  setBrandFilter={setBrandFilter}
                  availableCalibers={availableCalibers}
                  caliberFilter={caliberFilter}
                  setCaliberFilter={setCaliberFilter}
                  priceBounds={priceBounds}
                  priceRange={priceRange}
                  setPriceRange={setPriceRange}
                  inStockOnly={inStockOnly}
                  setInStockOnly={setInStockOnly}
                />
              </aside>
            )}

            <div className="flex-1">
              {!loading && !error && (
                <SortBar
                  visibleRange={visibleRange}
                  totalCount={serverTotalElements}
                  searchQuery={searchQuery}
                  setSearchQuery={setSearchQuery}
                  sortBy={sortBy}
                  setSortBy={setSortBy}
                />
              )}

              {loading ? (
                <p className="py-8 text-center text-sm text-zinc-500">
                  Loading…
                </p>
              ) : error ? (
                <p className="py-8 text-center text-sm text-red-400">{error}</p>
              ) : serverTotalElements === 0 ? (
                <p className="py-8 text-center text-sm text-zinc-500">
                  No parts found for this role yet.
                </p>
              ) : (
                <PartsGrid
                  viewMode={viewMode}
                  parts={paginatedParts}
                  buildDetailHref={(p) =>
                    buildDetailHref(effectivePlatform, partRole, p)
                  }
                  onAddToBuild={handleAddToBuild}
                  addLabel="Add to Build"
                />
              )}

              {totalPages > 1 && (
                <Pagination
                  currentPage={currentPage}
                  totalPages={totalPages}
                  onPrev={() => setCurrentPage((p) => Math.max(1, p - 1))}
                  onNext={() =>
                    setCurrentPage((p) => Math.min(totalPages, p + 1))
                  }
                />
              )}
            </div>
          </div>
        </section>
      </div>
    </main>
  );
}
