"use client";

import { useEffect, useMemo, useState } from "react";

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

type PendingBucket = {
  merchantId: number;
  merchantName: string;
  rawCategoryKey: string;
  mappedPartRole: string | null;
  productCount: number;
};

/**
 * Canonical part roles (kebab-case) — should match what the importer normalizes to.
 * Keep this list tight + intentional so mappings don't create junk roles in the DB.
 */
const PART_ROLE_OPTIONS = [
  // Assemblies / receivers
  "upper-receiver",
  "complete-upper",
  "lower-receiver",
  "complete-lower",

  // Upper sub-parts
  "bcg",
  "barrel",
  "gas-block",
  "gas-tube",
  "muzzle-device",
  "suppressor",
  "handguard",
  "charging-handle",

  // Lower sub-parts
  "lower-parts",
  "trigger",
  "grip",
  "safety",
  "buffer",
  "stock",

  // Sights / optics
  "sights",
  "optic",

  // Accessories / gear
  "magazine",
  "weapon-light",
  "foregrip",
  "bipod",
  "sling",
  "rail-accessory",
  "tools",
] as const;

type PartRole = (typeof PART_ROLE_OPTIONS)[number];

function toLabel(role: string) {
  // "complete-upper" -> "Complete Upper"
  return role
    .split("-")
    .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
    .join(" ");
}

export default function MappingAdminPage() {
  const [rows, setRows] = useState<PendingBucket[]>([]);
  const [loading, setLoading] = useState(true);
  const [savingKey, setSavingKey] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  const options = useMemo(
    () =>
      PART_ROLE_OPTIONS.map((value) => ({
        value,
        label: toLabel(value),
      })),
    []
  );

  useEffect(() => {
    async function load() {
      try {
        setLoading(true);
        setError(null);

        const res = await fetch(
          `${API_BASE_URL}/api/admin/mapping/pending-buckets`,
          { headers: { Accept: "application/json" } }
        );

        if (!res.ok) {
          const text = await res.text().catch(() => "");
          throw new Error(
            `Failed to load pending buckets (${res.status})${text ? `: ${text}` : ""}`
          );
        }

        const data: PendingBucket[] = await res.json();
        setRows(data);
      } catch (e: any) {
        console.error(e);
        setError(e.message ?? "Failed to load pending buckets");
      } finally {
        setLoading(false);
      }
    }

    load();
  }, []);

  const handleChangeRole = (idx: number, value: string) => {
    // Always store normalized kebab-case (defensive)
    const normalized = value
      ? value.trim().toLowerCase().replace(/_/g, "-")
      : "";

    setRows((prev) => {
      const next = [...prev];
      next[idx] = { ...next[idx], mappedPartRole: normalized || null };
      return next;
    });
  };

  const handleSave = async (row: PendingBucket) => {
    if (!row.mappedPartRole) return;

    const mapped = row.mappedPartRole
      .trim()
      .toLowerCase()
      .replace(/_/g, "-");

    // Basic guard: prevent saving random roles from stale data
    const allowed = new Set<string>(PART_ROLE_OPTIONS as readonly string[]);
    if (!allowed.has(mapped)) {
      setError(
        `Refusing to save unknown part role: "${row.mappedPartRole}". Pick a role from the dropdown list.`
      );
      return;
    }

    const key = `${row.merchantId}-${row.rawCategoryKey}`;
    try {
      setSavingKey(key);
      setError(null);

      const res = await fetch(`${API_BASE_URL}/api/admin/mapping/apply`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          merchantId: row.merchantId,
          rawCategoryKey: row.rawCategoryKey,
          mappedPartRole: mapped,
        }),
      });

      if (!res.ok) {
        const text = await res.text().catch(() => "");
        throw new Error(
          `Failed to save mapping (${res.status})${text ? `: ${text}` : ""}`
        );
      }

      // After save, remove this bucket from the list
      setRows((prev) =>
        prev.filter(
          (r) =>
            !(
              r.merchantId === row.merchantId &&
              r.rawCategoryKey === row.rawCategoryKey
            )
        )
      );
    } catch (e: any) {
      console.error(e);
      setError(e.message ?? "Failed to save mapping");
    } finally {
      setSavingKey(null);
    }
  };

  return (
    <main className="min-h-screen bg-black text-zinc-50">
      <div className="mx-auto max-w-6xl px-4 py-6">
        <h1 className="text-xl font-semibold tracking-tight">
          Bulk Mapping – Pending Categories
        </h1>
        <p className="mt-1 text-sm text-zinc-400">
          Bucketed by merchant + raw category. Map each bucket to a part role to
          clean up the builder catalog.
        </p>

        {loading && (
          <p className="mt-4 text-sm text-zinc-400">Loading pending buckets…</p>
        )}

        {error && (
          <p className="mt-4 text-sm text-red-400">Error: {error}</p>
        )}

        {!loading && rows.length === 0 && !error && (
          <p className="mt-4 text-sm text-emerald-400">
            No pending mapping buckets 🎉
          </p>
        )}

        {!loading && rows.length > 0 && (
          <section className="mt-4 rounded-lg border border-zinc-800 bg-zinc-950/80 p-3">
            <div className="mb-2 flex items-center justify-between">
              <h2 className="text-xs font-semibold uppercase tracking-[0.14em] text-zinc-500">
                Pending Buckets
              </h2>
              <span className="text-xs text-zinc-400">
                {rows.length} buckets •{" "}
                {rows.reduce((s, r) => s + r.productCount, 0)} products
              </span>
            </div>

            <div className="mt-1 overflow-x-auto">
              <table className="min-w-full text-xs">
                <thead>
                  <tr className="border-b border-zinc-800 bg-zinc-900/60">
                    <th className="px-2 py-1 text-left text-zinc-400">
                      Merchant
                    </th>
                    <th className="px-2 py-1 text-left text-zinc-400">
                      Raw Category
                    </th>
                    <th className="px-2 py-1 text-left text-zinc-400">
                      Products
                    </th>
                    <th className="px-2 py-1 text-left text-zinc-400">
                      Part Role
                    </th>
                    <th className="px-2 py-1 text-right text-zinc-400">
                      Action
                    </th>
                  </tr>
                </thead>
                <tbody>
                  {rows.map((row, idx) => {
                    const rowKey = `${row.merchantId}-${row.rawCategoryKey}`;
                    const isSaving = savingKey === rowKey;

                    return (
                      <tr
                        key={rowKey}
                        className="border-b border-zinc-900 hover:bg-zinc-900/40"
                      >
                        <td className="px-2 py-1 text-zinc-100">
                          {row.merchantName}
                        </td>
                        <td className="px-2 py-1 text-zinc-300">
                          {row.rawCategoryKey}
                        </td>
                        <td className="px-2 py-1 text-zinc-200">
                          {row.productCount}
                        </td>
                        <td className="px-2 py-1 text-zinc-100">
                          <select
                            className="w-full rounded-md border border-zinc-700 bg-zinc-950/80 px-2 py-1 text-xs text-zinc-100 outline-none focus:border-amber-400"
                            value={row.mappedPartRole ?? ""}
                            onChange={(e) =>
                              handleChangeRole(idx, e.target.value)
                            }
                          >
                            <option value="">Select part role…</option>
                            {options.map((opt) => (
                              <option key={opt.value} value={opt.value}>
                                {opt.label} ({opt.value})
                              </option>
                            ))}
                          </select>
                        </td>
                        <td className="px-2 py-1 text-right">
                          <button
                            onClick={() => handleSave(row)}
                            disabled={!row.mappedPartRole || isSaving}
                            className="rounded-md bg-emerald-500 px-3 py-1 text-[0.7rem] font-semibold text-black disabled:cursor-not-allowed disabled:bg-zinc-700"
                          >
                            {isSaving ? "Saving…" : "Save"}
                          </button>
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          </section>
        )}
      </div>
    </main>
  );
}