"use client";

import Link from "next/link";
import { usePathname } from "next/navigation";

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

import { useEffect, useMemo, useState } from "react";
import { 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 type { CategoryId } from "@/types/gunbuilder";
import {
  PART_ROLE_TO_CATEGORY,
  normalizePartRole,
} from "@/lib/catalogMappings";

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;
  mainImageUrl: string | null;
  buyUrl: string | null;
  inStock?: boolean | null;
};

type UiPart = {
  id: string;
  name: string;
  brand: string;
  platform: string;
  partRole: string;
  price: number; // normalized
  imageUrl?: string;
  buyUrl?: string;
  inStock?: boolean;
};

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();

  const effectivePlatform =
    props.platform ?? searchParams.get("platform") ?? "AR-15";
  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 [sortBy, setSortBy] = useState<SortOption>("relevance");
  const [searchQuery, setSearchQuery] = useState<string>("");
  const [priceRange, setPriceRange] = useState<{
    min: number | null;
    max: number | null;
  }>({
    min: null,
    max: null,
  });
  const [inStockOnly, setInStockOnly] = useState(false);
  const [currentPage, setCurrentPage] = useState(1);

  useEffect(() => {
    if (!partRole) return;

    const controller = new AbortController();

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

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

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

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

        const data: GunbuilderProductFromApi[] = await res.json();

        const normalized: UiPart[] = data.map((p) => ({
          id: normalizeId(p.id),
          name: p.name,
          brand: p.brand,
          platform: p.platform,
          partRole: p.partRole,
          price: p.price ?? 0,
          imageUrl: p.mainImageUrl ?? undefined,
          buyUrl: p.buyUrl ?? undefined,
          inStock: p.inStock ?? true,
        }));

        setParts(normalized);
      } catch (err: any) {
        if (err?.name === "AbortError") return;
        setError(err?.message ?? "Failed to load products");
      } finally {
        setLoading(false);
      }
    }

    fetchParts();
    return () => controller.abort();
  }, [partRole, effectivePlatform]);

  useEffect(() => {
    setCurrentPage(1);
  }, [
    partRole,
    effectivePlatform,
    brandFilter,
    sortBy,
    searchQuery,
    priceRange,
    inStockOnly,
  ]);

  useEffect(() => {
    // Reset scroll position whenever we land on or change parts routes
    window.scrollTo({ top: 0, left: 0, behavior: "auto" });
  }, [pathname]);

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

  const priceBounds = useMemo(() => {
    if (parts.length === 0)
      return { min: null as number | null, max: null as number | null };

    let min = Number.POSITIVE_INFINITY;
    let max = Number.NEGATIVE_INFINITY;

    for (const p of parts) {
      const price = p.price ?? 0;
      if (price < min) min = price;
      if (price > max) max = price;
    }

    if (!Number.isFinite(min) || !Number.isFinite(max)) {
      return { min: null as number | null, max: null as number | null };
    }

    return { min, max };
  }, [parts]);

  useEffect(() => {
    if (priceBounds.min == null || priceBounds.max == null) return;

    setPriceRange((prev) => {
      const min = prev.min ?? priceBounds.min!;
      const max = prev.max ?? priceBounds.max!;
      return {
        min: Math.max(priceBounds.min!, Math.min(min, priceBounds.max!)),
        max: Math.min(priceBounds.max!, Math.max(max, priceBounds.min!)),
      };
    });
  }, [priceBounds.min, priceBounds.max]);

  const filteredParts = useMemo(() => {
    let result = [...parts];

    const effectiveMin = priceRange.min ?? priceBounds.min;
    const effectiveMax = priceRange.max ?? priceBounds.max;
    if (effectiveMin != null && effectiveMax != null) {
      result = result.filter(
        (p) => p.price >= effectiveMin && p.price <= effectiveMax
      );
    }

    if (brandFilter.length > 0) {
      result = result.filter((p) => brandFilter.includes(p.brand));
    }

    if (inStockOnly) {
      result = result.filter((p) => p.inStock ?? true);
    }

    const q = searchQuery.trim().toLowerCase();
    if (q) {
      result = result.filter((p) => {
        const name = (p.name ?? "").toLowerCase();
        const brand = (p.brand ?? "").toLowerCase();
        return name.includes(q) || brand.includes(q);
      });
    }

    switch (sortBy) {
      case "price-asc":
        result.sort((a, b) => a.price - b.price);
        break;
      case "price-desc":
        result.sort((a, b) => b.price - a.price);
        break;
      case "brand-asc":
        result.sort((a, b) => a.brand.localeCompare(b.brand));
        break;
      case "relevance":
      default:
        break;
    }

    return result;
  }, [
    parts,
    brandFilter,
    sortBy,
    searchQuery,
    priceRange,
    priceBounds.min,
    priceBounds.max,
    inStockOnly,
  ]);

  const totalPages = useMemo(
    () =>
      filteredParts.length === 0
        ? 1
        : Math.ceil(filteredParts.length / PAGE_SIZE),
    [filteredParts.length]
  );

  const paginatedParts = useMemo(() => {
    if (filteredParts.length === 0) return [];
    const startIndex = (currentPage - 1) * PAGE_SIZE;
    return filteredParts.slice(startIndex, startIndex + PAGE_SIZE);
  }, [filteredParts, currentPage]);

  const visibleRange = useMemo(() => {
    if (filteredParts.length === 0) return { start: 0, end: 0 };
    const start = (currentPage - 1) * PAGE_SIZE + 1;
    const end = Math.min(
      start + paginatedParts.length - 1,
      filteredParts.length
    );
    return { start, end };
  }, [filteredParts.length, currentPage, paginatedParts.length]);

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

  // ✅ Add-to-build handler: deep-links into builder’s existing ?select= logic
  const handleAddToBuild = (p: UiPart) => {
    const normalizedRole = normalizePartRole(partRole);
    const categoryId: CategoryId | null =
      PART_ROLE_TO_CATEGORY[partRole] ??
      PART_ROLE_TO_CATEGORY[normalizedRole] ??
      null;

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

    const qp = new URLSearchParams();
    qp.set("platform", 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">
          <div className="flex items-start 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 tracking-tight">
                {headingTitle}{" "}
                <span className="text-amber-300">{effectivePlatform}</span>
              </h1>

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

              <div className="mt-3">
                <PlatformSwitcher
                  currentPlatform={effectivePlatform}
                  partRole={partRole}
                  preserveQuery
                />
              </div>
            </div>

            {!loading && !error && (
              <div className="flex items-center gap-2">
                <Link
                  href={{
                    pathname: "/builder",
                    query: effectivePlatform
                      ? { platform: effectivePlatform }
                      : {},
                  }}
                  className="rounded-md border border-zinc-700 bg-zinc-900/70 px-3 py-2 text-xs font-semibold text-zinc-200 hover:bg-zinc-800"
                >
                  ← Back to Build
                </Link>

                {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>
            )}
          </div>
        </header>

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

            <div className="flex-1">
              {!loading && !error && parts.length > 0 && (
                <SortBar
                  visibleRange={visibleRange}
                  totalCount={filteredParts.length}
                  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} — check that the Ballistic API is running.
                </p>
              ) : filteredParts.length === 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"
                />
              )}

              {!loading &&
                !error &&
                filteredParts.length > 0 &&
                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>
  );
}
