"use client";

/**
 * app/builds/page.tsx
 * Community Builds feed (public)
 *
 * Dev Notes:
 * - We are moving to Option B:
 *   Build (core) + BuildProfile (meta) + Votes/Comments/Media as separate tables.
 * - This page expects a lightweight "feed card" DTO from the backend, NOT full build items.
 * - Keep UI/filters here client-side for MVP; move to server-side query params later if needed.
 *
 * Backend (target contract):
 *   GET /api/v1/builds?limit=50  -> BuildFeedCardDto[]
 *   (Optional later) POST /api/v1/builds/{uuid}/vote { delta: 1 | -1 }
 */

import { useEffect, useMemo, useState, useCallback } from "react";
import Link from "next/link";

type BuildClass = "Rifle" | "Pistol" | "NFA";

/**
 * Keep this loose. Backend will control the allowed calibers via BuildProfile.
 * We can tighten once the controlled vocab is finalized.
 */
type Caliber = string;

/**
 * This matches what the UI needs (card format).
 * It maps cleanly to: builds + build_profiles + aggregated votes (+ optional price).
 */
type BuildCard = {
  id: string; // we use uuid here (public identifier)
  title: string;
  slug: string; // can be uuid for now; keep property so UI does not change
  creator: string; // placeholder until user profiles are real
  caliber: Caliber;
  buildClass: BuildClass;
  price: number; // optional server-side later; for now allow 0 fallback
  votes: number;
  tags: string[];
  coverImageUrl?: string | null;
};

type BuildFeedCardDto = {
  uuid: string;
  title?: string | null;
  slug?: string | null; // optional (we can generate from title later)
  creator?: string | null; // optional
  caliber?: string | null;
  buildClass?: BuildClass | null;
  price?: number | null;
  votes?: number | null;
  tags?: string[] | null;
  coverImageUrl?: string | null;
};

const API_BASE_URL =
  process.env.NEXT_PUBLIC_API_BASE_URL ?? "";

// --- UI Filter Sets (keep; we’ll generate options from data too) ---
const CLASS_FILTERS: (BuildClass | "all")[] = ["all", "Rifle", "Pistol", "NFA"];

const PRICE_FILTERS = [
  { id: "all", label: "All", min: 0, max: Infinity },
  { id: "sub1k", label: "< $1k", min: 0, max: 1000_00 },
  { id: "1to2k", label: "$1k–$2k", min: 1000_00, max: 2000_00 },
  { id: "2to3k", label: "$2k–$3k", min: 2000_00, max: 3000_00 },
  { id: "3kplus", label: "$3k+", min: 3000_00, max: Infinity },
];

function safeArray(v: unknown): string[] {
  return Array.isArray(v) ? v.filter(Boolean).map(String) : [];
}

function fallbackSlug(dto: BuildFeedCardDto) {
  // MVP: stable route id is uuid. Keep a "slug" field for UI continuity.
  return dto.slug?.trim() || dto.uuid;
}

function normalizeCard(dto: BuildFeedCardDto): BuildCard {
  const title = (dto.title ?? "Untitled Build").trim() || "Untitled Build";

  return {
    id: dto.uuid,
    title,
    slug: fallbackSlug(dto),

    // Until we wire real users: keep a placeholder creator string.
    creator: (dto.creator ?? "anonymous").trim() || "anonymous",

    caliber: (dto.caliber ?? "—").trim() || "—",

    // Default to Rifle for display if missing; backend should set this via profile.
    buildClass: (dto.buildClass ?? "Rifle") as BuildClass,

    // Price is optional (we can compute later from BuildItems + offers).
    price: typeof dto.price === "number" ? dto.price : 0,

    votes: typeof dto.votes === "number" ? dto.votes : 0,

    tags: safeArray(dto.tags),

    coverImageUrl: dto.coverImageUrl ?? null,
  };
}

export default function BuildsPage() {
  // --- Remote data state ---
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [builds, setBuilds] = useState<BuildCard[]>([]);

  // --- UI state (filters/votes) ---
  const [caliberFilter, setCaliberFilter] = useState<Caliber | "all">("all");
  const [classFilter, setClassFilter] = useState<BuildClass | "all">("all");
  const [priceFilterId, setPriceFilterId] = useState<string>("all");

  // Local vote state for optimistic UI
  const [votes, setVotes] = useState<Record<string, number>>({});

  const activePriceFilter =
    PRICE_FILTERS.find((p) => p.id === priceFilterId) ?? PRICE_FILTERS[0];

  // --- Fetch public builds feed ---
  useEffect(() => {
    let cancelled = false;

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

        const res = await fetch('/api/builds/public?limit=50', {
          method: "GET",
          credentials: "include",
          headers: { "Content-Type": "application/json" },
        });

        if (!res.ok) {
          const txt = await res.text().catch(() => "");
          throw new Error(txt || `Failed to load builds (${res.status})`);
        }

        const data = (await res.json()) as BuildFeedCardDto[];
        const cards = (Array.isArray(data) ? data : []).map(normalizeCard);

        if (cancelled) return;

        setBuilds(cards);

        // Initialize vote UI from payload totals
        setVotes(Object.fromEntries(cards.map((b) => [b.id, b.votes])));
      } catch (e: any) {
        if (!cancelled) setError(e?.message || "Failed to load builds feed");
      } finally {
        if (!cancelled) setLoading(false);
      }
    }

    run();
    return () => {
      cancelled = true;
    };
  }, []);

  // Build the caliber filters dynamically from data, but keep "all" first.
  const CALIBER_FILTERS = useMemo<(Caliber | "all")[]>(() => {
    const uniq = new Set<string>();
    for (const b of builds) {
      const c = (b.caliber ?? "").trim();
      if (c && c !== "—") uniq.add(c);
    }
    return ["all", ...Array.from(uniq).sort()];
  }, [builds]);

  const filteredBuilds = useMemo(() => {
    return builds.filter((build) => {
      const matchesCaliber =
        caliberFilter === "all" || build.caliber === caliberFilter;

      const matchesClass =
        classFilter === "all" || build.buildClass === classFilter;

      const matchesPrice =
        build.price >= activePriceFilter.min &&
        build.price < activePriceFilter.max;

      return matchesCaliber && matchesClass && matchesPrice;
    });
  }, [builds, caliberFilter, classFilter, activePriceFilter]);

  const handleVote = useCallback((id: string, delta: 1 | -1) => {
    // MVP: optimistic local vote only.
    // Later: POST /api/v1/builds/{uuid}/vote { delta } and reconcile.
    setVotes((prev) => ({
      ...prev,
      [id]: (prev[id] ?? 0) + delta,
    }));
  }, []);

  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 */}
        <header className="mb-6 flex flex-col gap-4 md:flex-row md:items-end md:justify-between">
          <div>
            <p className="text-xs font-semibold tracking-[0.2em] uppercase text-zinc-500">
              Battl Builder · Build Book
            </p>
            <h1
              className="mt-2 text-3xl md:text-4xl font-extrabold tracking-tight
                         bg-gradient-to-r from-amber-400 via-amber-200 to-amber-400
                         text-transparent bg-clip-text drop-shadow-[0_2px_6px_rgba(255,193,7,0.25)]"
            >
              Community Builds
            </h1>
            <p className="mt-2 text-sm md:text-base text-zinc-400 max-w-xl">
              Browse community builds, vote them up or down, and steal good
              ideas without shame. This feed is backed by public builds
              (isPublic=true).
            </p>
          </div>

          <div className="flex gap-2 md:gap-3">
            <Link
              href="/builder"
              className="inline-flex items-center justify-center rounded-md border border-zinc-700 bg-zinc-900/60 px-4 py-2 text-xs md:text-sm font-medium text-zinc-200 hover:bg-zinc-800 hover:border-zinc-600 transition-colors"
            >
              Open Builder
            </Link>

            {/* Later: route to /vault + choose build to submit, or direct /builder submit flow */}
            <Link
              href="/vault"
              className="inline-flex items-center justify-center rounded-md border border-amber-400/70 bg-amber-400/10 px-4 py-2 text-xs md:text-sm font-medium text-amber-200 hover:bg-amber-400/15 transition-colors"
            >
              + Submit Build
            </Link>
          </div>
        </header>

        {/* Loading / Error */}
        {loading && (
          <div className="mb-6 rounded-lg border border-zinc-800 bg-zinc-950/70 p-4 text-sm text-zinc-400">
            Loading community builds…
          </div>
        )}

        {error && !loading && (
          <div className="mb-6 rounded-lg border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-200">
            {error}
            <div className="mt-2 text-xs text-red-200/80">
              Dev tip: confirm backend route{" "}
              <span className="font-mono">GET /api/v1/builds</span> is
              implemented + CORS is configured.
            </div>
          </div>
        )}

        {/* Filters */}
        <section className="mb-6 rounded-lg border border-zinc-800 bg-zinc-950/70 p-4 space-y-4">
          <div className="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
            <div>
              <h2 className="text-xs font-semibold tracking-[0.16em] uppercase text-zinc-400">
                Filter Builds
              </h2>
              <p className="text-xs text-zinc-500 mt-1">
                Filter by caliber, class, and price range. (Client-side for
                MVP.)
              </p>
            </div>

            <div className="text-xs text-zinc-500">
              Showing{" "}
              <span className="text-zinc-200 font-medium">
                {filteredBuilds.length}
              </span>{" "}
              of{" "}
              <span className="text-zinc-200 font-medium">{builds.length}</span>{" "}
              builds
            </div>
          </div>

          <div className="grid gap-3 md:grid-cols-3">
            {/* Caliber filter */}
            <div>
              <div className="text-[0.7rem] uppercase tracking-[0.16em] text-zinc-500 mb-1">
                Caliber
              </div>
              <div className="flex flex-wrap gap-2">
                {CALIBER_FILTERS.map((caliber) => (
                  <button
                    key={caliber}
                    type="button"
                    onClick={() =>
                      setCaliberFilter(caliber === "all" ? "all" : caliber)
                    }
                    className={`rounded-full border px-3 py-1 text-xs transition-colors ${
                      caliberFilter === caliber
                        ? "border-amber-400/70 bg-amber-400/10 text-amber-200"
                        : "border-zinc-700 bg-zinc-900/60 text-zinc-300 hover:bg-zinc-800 hover:border-zinc-600"
                    }`}
                  >
                    {caliber === "all" ? "All" : caliber}
                  </button>
                ))}
              </div>
            </div>

            {/* Class filter */}
            <div>
              <div className="text-[0.7rem] uppercase tracking-[0.16em] text-zinc-500 mb-1">
                Class
              </div>
              <div className="flex flex-wrap gap-2">
                {CLASS_FILTERS.map((cls) => (
                  <button
                    key={cls}
                    type="button"
                    onClick={() => setClassFilter(cls === "all" ? "all" : cls)}
                    className={`rounded-full border px-3 py-1 text-xs transition-colors ${
                      classFilter === cls
                        ? "border-amber-400/70 bg-amber-400/10 text-amber-200"
                        : "border-zinc-700 bg-zinc-900/60 text-zinc-300 hover:bg-zinc-800 hover:border-zinc-600"
                    }`}
                  >
                    {cls === "all" ? "All" : cls}
                  </button>
                ))}
              </div>
            </div>

            {/* Price filter */}
            <div>
              <div className="text-[0.7rem] uppercase tracking-[0.16em] text-zinc-500 mb-1">
                Price Range
              </div>
              <div className="flex flex-wrap gap-2">
                {PRICE_FILTERS.map((range) => (
                  <button
                    key={range.id}
                    type="button"
                    onClick={() => setPriceFilterId(range.id)}
                    className={`rounded-full border px-3 py-1 text-xs transition-colors ${
                      priceFilterId === range.id
                        ? "border-amber-400/70 bg-amber-400/10 text-amber-200"
                        : "border-zinc-700 bg-zinc-900/60 text-zinc-300 hover:bg-zinc-800 hover:border-zinc-600"
                    }`}
                  >
                    {range.label}
                  </button>
                ))}
              </div>
            </div>
          </div>
        </section>

        {/* Build list */}
        <section>
          <div className="space-y-4">
            {filteredBuilds.map((build) => {
              const dollars = Math.floor((build.price ?? 0) / 100);

              return (
                <article
                  key={build.id}
                  className="flex gap-4 rounded-lg border border-zinc-800 bg-zinc-950/70 p-4"
                >
                  {/* Votes column */}
                  <div className="flex flex-col items-center justify-center gap-1">
                    <button
                      type="button"
                      onClick={() => handleVote(build.id, 1)}
                      className="flex h-6 w-6 items-center justify-center rounded-full border border-zinc-700 bg-zinc-900/70 text-xs text-zinc-300 hover:bg-zinc-800 hover:border-zinc-500"
                      aria-label="Upvote"
                      title="Upvote"
                    >
                      ▲
                    </button>
                    <div className="text-xs font-semibold text-amber-200">
                      {votes[build.id] ?? build.votes}
                    </div>
                    <button
                      type="button"
                      onClick={() => handleVote(build.id, -1)}
                      className="flex h-6 w-6 items-center justify-center rounded-full border border-zinc-700 bg-zinc-900/70 text-xs text-zinc-300 hover:bg-zinc-800 hover:border-zinc-500"
                      aria-label="Downvote"
                      title="Downvote"
                    >
                      ▼
                    </button>
                  </div>

                  {/* Thumbnail */}
                  <div className="hidden sm:block">
                    <div className="overflow-hidden rounded-md border border-zinc-800 bg-zinc-900/80 h-24 w-40">
                      {/* eslint-disable-next-line @next/next/no-img-element */}
                      <img
                        src={
                          build.coverImageUrl ||
                          "https://placehold.co/320x200/png?text=Build+Photo"
                        }
                        alt={`${build.title} cover`}
                        className="h-full w-full object-cover"
                      />
                    </div>
                  </div>

                  {/* Main content */}
                  <div className="flex-1">
                    <div className="flex flex-col gap-2 md:flex-row md:items-start md:justify-between">
                      <div>
                        <div className="text-[0.7rem] uppercase tracking-[0.16em] text-zinc-500 mb-1">
                          {build.buildClass} · {build.caliber}
                        </div>
                        <h3 className="text-lg md:text-xl font-semibold text-zinc-50">
                          <Link
                            href={`/builds/${build.slug}`}
                            className="hover:text-amber-200 transition-colors"
                          >
                            {build.title}
                          </Link>
                        </h3>
                        <p className="text-xs text-zinc-500 mt-1">
                          Posted by{" "}
                          <span className="text-zinc-300">
                            b/{build.creator}
                          </span>{" "}
                          · Build detail page will show the parts list +
                          comments.
                        </p>
                      </div>

                      <div className="text-right mt-1 md:mt-0">
                        <div className="text-xs uppercase tracking-[0.16em] text-zinc-500">
                          Est. Build Cost
                        </div>
                        <div className="text-lg font-semibold text-amber-300">
                          {build.price > 0 ? (
                            <span>
                              ${Math.floor(build.price / 100).toLocaleString()}
                            </span>
                          ) : (
                            "—"
                          )}
                        </div>
                      </div>
                    </div>

                    <div className="mt-3 flex flex-wrap items-center gap-2">
                      {build.tags.map((tag) => (
                        <span
                          key={tag}
                          className="rounded-full border border-zinc-700 bg-zinc-900/60 px-2 py-0.5 text-[0.7rem] text-zinc-400"
                        >
                          {tag}
                        </span>
                      ))}

                      <span className="ml-auto text-[0.7rem] text-zinc-500">
                        Comments + save coming soon.
                      </span>
                    </div>
                  </div>
                </article>
              );
            })}

            {!loading && !error && filteredBuilds.length === 0 && (
              <div className="rounded-lg border border-zinc-800 bg-zinc-950/70 p-6 text-center text-sm text-zinc-500">
                No builds match those filters yet.
              </div>
            )}
          </div>
        </section>
      </div>
    </main>
  );
}
