"use client";

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

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

type Merchant = {
  id: number;
  name: string;
};

type Mapping = {
  id: number | null;           // might be null if just created client-side
  merchantId: number;
  merchantName: string;
  rawCategory: string;
  mappedPartRole: string | null;
};

type UpsertRequest = {
  merchantId: number;
  rawCategory: string;
  mappedPartRole: string | null;
};

// Keep this in sync with your backend `partRole` values
const PART_ROLE_OPTIONS = [
  { value: "", label: "— Unmapped —" },
  { value: "upper-receiver", label: "Upper Receiver" },
  { value: "barrel", label: "Barrel" },
  { value: "handguard", label: "Handguard" },
  { value: "charging-handle", label: "Charging Handle" },
  { value: "buffer-kit", label: "Buffer Kit" },
  { value: "lower-parts-kit", label: "Lower Parts Kit" },
  { value: "sight", label: "Sight / Optic" },
  { value: "lower-receiver", label: "Lower Receiver" },
  { value: "optic", label: "Optic" },
  { value: "stock", label: "Stock" },
  { value: "other", label: "Other / Ignore" },
];

export default function CategoryMappingsPage() {
  const [merchants, setMerchants] = useState<Merchant[]>([]);
  const [selectedMerchantId, setSelectedMerchantId] = useState<number | null>(
    null,
  );
  const [mappings, setMappings] = useState<Mapping[]>([]);
  const [loadingMappings, setLoadingMappings] = useState(false);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);
  const [showOnlyUnmapped, setShowOnlyUnmapped] = useState(false);

  const sortedMappings = useMemo(() => {
    // Mapped rows first, then unmapped; within each group, alpha by rawCategory
    return [...mappings].sort((a, b) => {
      const aMapped = !!a.mappedPartRole;
      const bMapped = !!b.mappedPartRole;

      if (aMapped !== bMapped) {
        return aMapped ? -1 : 1; // mapped first
      }

      return a.rawCategory.localeCompare(b.rawCategory);
    });
  }, [mappings]);

  const visibleMappings = useMemo(
    () =>
      showOnlyUnmapped
        ? sortedMappings.filter((m) => !m.mappedPartRole)
        : sortedMappings,
    [sortedMappings, showOnlyUnmapped],
  );

  // Load merchants
  useEffect(() => {
    async function fetchMerchants() {
      try {
        const res = await fetch(`${API_BASE_URL}/admin/merchants`);
        if (!res.ok) {
          throw new Error(`Failed to load merchants (${res.status})`);
        }
        const data: Merchant[] = await res.json();
        setMerchants(data);

        // Auto-select the first merchant if you want
        if (data.length > 0 && selectedMerchantId === null) {
          setSelectedMerchantId(data[0].id);
        }
      } catch (err: any) {
        console.error(err);
        setError(err.message ?? "Failed to load merchants");
      }
    }

    fetchMerchants();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Load mappings for selected merchant
  useEffect(() => {
    if (!selectedMerchantId) return;

    const controller = new AbortController();

    async function fetchMappings() {
      try {
        setLoadingMappings(true);
        setError(null);
        setSuccessMessage(null);

        const url = `${API_BASE_URL}/admin/merchant-category-mappings?merchantId=${selectedMerchantId}`;
        const res = await fetch(url, { signal: controller.signal });

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

        const data = (await res.json()) as Mapping[];
        setMappings(data);
      } catch (err: any) {
        if (err.name === "AbortError") return;
        console.error(err);
        setError(err.message ?? "Failed to load mappings");
      } finally {
        setLoadingMappings(false);
      }
    }

    fetchMappings();

    return () => controller.abort();
  }, [selectedMerchantId]);

  const handleChangePartRole = (rawCategory: string, newRole: string) => {
    setMappings((prev) =>
      prev.map((m) =>
        m.rawCategory === rawCategory
          ? { ...m, mappedPartRole: newRole || null }
          : m,
      ),
    );
  };

  const handleSave = async () => {
    if (!selectedMerchantId) return;
    setSaving(true);
    setError(null);
    setSuccessMessage(null);

    try {
      // Save each mapping in parallel
      const requests: Promise<Response>[] = mappings.map((m) => {
        const payload: UpsertRequest = {
          merchantId: selectedMerchantId,
          rawCategory: m.rawCategory,
          mappedPartRole: m.mappedPartRole,
        };

        return fetch(`${API_BASE_URL}/admin/merchant-category-mappings`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
        });
      });

      const responses = await Promise.all(requests);
      const failed = responses.filter((r) => !r.ok);

      if (failed.length > 0) {
        throw new Error(`Some mappings failed to save (${failed.length})`);
      }

      setSuccessMessage("Mappings saved. Re-run the import to apply changes.");
    } catch (err: any) {
      console.error(err);
      setError(err.message ?? "Failed to save mappings");
    } finally {
      setSaving(false);
    }
  };

  const selectedMerchantName =
    merchants.find((m) => m.id === selectedMerchantId)?.name ?? "—";

  return (
    <main className="min-h-screen bg-black text-zinc-50">
      <div className="mx-auto max-w-5xl px-4 py-6 lg:py-10">
        <header className="mb-6 flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
          <div>
            <p className="text-xs font-semibold tracking-[0.2em] uppercase text-zinc-500">
              Shadow Standard / Admin
            </p>
            <h1 className="mt-1 text-2xl md:text-3xl font-semibold tracking-tight">
              Merchant Category Mapping
            </h1>
            <p className="mt-2 text-sm text-zinc-400 max-w-xl">
              Normalize each merchant&apos;s category names into your internal
              part roles (upper, barrel, handguard, etc.). Unmapped categories
              will be skipped during import until they are mapped here.
            </p>
          </div>

          <div className="space-y-2">
            <label className="block text-xs font-semibold text-zinc-400 mb-1">
              Select Merchant
            </label>
            <select
              className="rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-100"
              value={selectedMerchantId ?? ""}
              onChange={(e) =>
                setSelectedMerchantId(
                  e.target.value ? Number(e.target.value) : null,
                )
              }
            >
              <option value="">— Choose merchant —</option>
              {merchants.map((m) => (
                <option key={m.id} value={m.id}>
                  {m.name}
                </option>
              ))}
            </select>
          </div>
        </header>

        <section className="rounded-lg border border-zinc-800 bg-zinc-950/60 p-3 md:p-4">
          {error && (
            <div className="mb-3 rounded border border-red-500/60 bg-red-500/10 px-3 py-2 text-xs text-red-200">
              {error}
            </div>
          )}
          {successMessage && (
            <div className="mb-3 rounded border border-emerald-500/60 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-200">
              {successMessage}
            </div>
          )}

          {!selectedMerchantId ? (
            <p className="text-sm text-zinc-500">
              Choose a merchant above to view category mappings.
            </p>
          ) : loadingMappings ? (
            <p className="text-sm text-zinc-500">
              Loading mappings for <span className="text-zinc-300">{selectedMerchantName}</span>…
            </p>
          ) : mappings.length === 0 ? (
            <p className="text-sm text-zinc-500">
              No category rows yet for this merchant. Once you run an import,
              discovered categories will appear here automatically.
            </p>
          ) : (
            <>
              <div className="mb-3 flex items-center justify-between gap-3 text-xs text-zinc-500">
                <div>
                  Mappings for{" "}
                  <span className="text-zinc-300">{selectedMerchantName}</span>.{" "}
                  Set a part role for each raw category. Unmapped categories will
                  be skipped by the importer.
                </div>
                <label className="inline-flex items-center gap-1 text-[0.7rem] text-zinc-400">
                  <input
                    type="checkbox"
                    className="h-3 w-3 rounded border-zinc-600 bg-zinc-900"
                    checked={showOnlyUnmapped}
                    onChange={(e) => setShowOnlyUnmapped(e.target.checked)}
                  />
                  <span>Show only unmapped</span>
                </label>
              </div>

              <div className="overflow-x-auto">
                <table className="min-w-full text-sm">
                  <thead>
                    <tr className="border-b border-zinc-800 text-xs uppercase tracking-[0.16em] text-zinc-500">
                      <th className="py-2 text-left pr-4">Raw Category</th>
                      <th className="py-2 text-left pr-4">Mapped Part Role</th>
                      <th className="py-2 text-left pr-4">Status</th>
                    </tr>
                  </thead>
                  <tbody>
                    {visibleMappings.map((m) => (
                      <tr
                        key={m.rawCategory}
                        className="border-b border-zinc-900 last:border-b-0"
                      >
                        <td className="py-2 pr-4 align-top text-zinc-200">
                          {m.rawCategory}
                        </td>
                        <td className="py-2 pr-4 align-top">
                          <select
                            className="rounded-md border border-zinc-700 bg-zinc-900 px-2 py-1 text-xs text-zinc-100"
                            value={m.mappedPartRole ?? ""}
                            onChange={(e) =>
                              handleChangePartRole(
                                m.rawCategory,
                                e.target.value,
                              )
                            }
                          >
                            {PART_ROLE_OPTIONS.map((opt) => (
                              <option key={opt.value} value={opt.value}>
                                {opt.label}
                              </option>
                            ))}
                          </select>
                        </td>
                        <td className="py-2 pr-4 align-top text-sm">
                          {m.mappedPartRole ? (
                            <span className="inline-flex items-center rounded-full bg-emerald-500/10 px-2 py-0.5 text-[0.7rem] font-medium text-emerald-300">
                              Mapped
                            </span>
                          ) : (
                            <span className="inline-flex items-center rounded-full bg-zinc-700/40 px-2 py-0.5 text-[0.7rem] font-medium text-zinc-300">
                              Unmapped / Ignored
                            </span>
                          )}
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>

              <div className="mt-4 flex justify-end">
                <button
                  type="button"
                  onClick={handleSave}
                  disabled={saving}
                  className="rounded-md bg-amber-400 px-4 py-2 text-sm font-semibold text-black hover:bg-amber-300 disabled:opacity-50"
                >
                  {saving ? "Saving…" : "Save Mappings"}
                </button>
              </div>
            </>
          )}
        </section>
      </div>
    </main>
  );
}