"use client";

import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { Loader2, Plus, X } from "lucide-react";

import type { ApiPriceDisplay, ApiProductPricing, ApiProductVariation, PriceOption } from "@/lib/api/types";
import { calcVariantExPrice, formatAmount } from "@/lib/pricing/forPrice";
import { saveRfqDraft, type RfqDraftVariation } from "@/lib/rfq/draft";
import { PRICE_OPTIONS } from "@/lib/rfq/priceOption";
import { moqMessage, quantityError } from "@/lib/validation";
import { formatUnit } from "@/lib/utils";

type Props = {
  productId: number;
  slug: string;
  name: string;
  thumbnail: string | null;
  minOrderQty: number;
  unit: string;
  brand: { id: number; name: string } | null;
  originCity: string | null;
  deliveryCity: string | null;
  variations: ApiProductVariation[];
  quality: { name: string; price: number }[];
  packaging: { id: number; name: string; charge: number }[];
  pricing: ApiProductPricing;
  /** Which price bases this listing exposes — the buyer picks between them. */
  display: ApiPriceDisplay;
};

/** The Price Option chips; the one selected is saved on the RFQ. */
type PriceBasis = PriceOption;

function chipClass(active: boolean) {
  return `flex items-center gap-1.5 rounded-lg border px-3 py-1.5 text-xs font-medium transition ${
    active
      ? "border-[#CC1414] bg-red-50 text-[#CC1414]"
      : "border-gray-200 bg-white text-gray-600 hover:border-gray-300"
  }`;
}

function valueLabel(entry: ApiProductVariation["value"][number] | undefined): string {
  if (!entry || entry.value === "" || entry.value === null) return "—";
  const short = entry.unit?.short_name;
  return short ? `${entry.value} ${short}` : String(entry.value);
}

function variationLabel(variation: ApiProductVariation): string {
  return valueLabel(variation.value?.[0]) || `#${variation.id}`;
}

/**
 * Variant selection and RFQ hand-off, ported from the legacy product detail
 * page (`biznie-app/src/View/Products/ProductDetail.js`).
 *
 * The buyer picks one quality and one packaging option, then any number of
 * variants; each selected variant becomes a row with its own quantity. The
 * per-row price mirrors the legacy `exCalc`: base price + total charges + the
 * variant's gauge difference + the chosen quality and packaging charge, then
 * GST. `pricing.total_charges` already contains loading, insurance and the
 * quality charge column, so those are never added a second time.
 *
 * Submitting stores the selection as an RFQ draft and sends the buyer to
 * `/rfq/new`, which is the App Router stand-in for the legacy
 * `navigate("/create-rfq", { state })`.
 */
export default function ProductRfqBuilder({
  productId,
  slug,
  name,
  thumbnail,
  minOrderQty,
  unit,
  brand,
  originCity,
  deliveryCity,
  variations,
  quality,
  packaging,
  pricing,
  display,
}: Props) {
  const router = useRouter();

  // The legacy page only offers variants the seller has enabled for the brand
  // it is selling.
  const sellable = useMemo(
    () =>
      variations.filter(
        (variation) => variation.is_selected === 1 && variation.is_brand_selling === 1
      ),
    [variations]
  );

  const groupLabel = sellable[0]?.value?.[0]?.name || "Size";

  const [selectedIds, setSelectedIds] = useState<number[]>([]);
  const [quantities, setQuantities] = useState<Record<number, string>>({});
  const [qualityIndex, setQualityIndex] = useState(0);
  const [packagingIndex, setPackagingIndex] = useState(0);
  const [error, setError] = useState<string | null>(null);
  const [pending, setPending] = useState(false);

  /* Only the bases the seller publishes. Ex-Works is the default when it is one
     of them, since every other number here is derived from it. */
  const bases = useMemo(() => {
    const enabled: PriceBasis[] = [];
    if (display.show_basic_price) enabled.push("basic");
    if (display.show_ex_price) enabled.push("ex_works");
    if (display.show_for_price) enabled.push("for");
    return enabled.length > 0 ? enabled : (["ex_works"] as PriceBasis[]);
  }, [display]);
  const [basis, setBasis] = useState<PriceBasis>(() => (bases.includes("ex_works") ? "ex_works" : bases[0]));

  const selectedQuality = quality[qualityIndex] ?? null;
  const selectedPackaging = packaging[packagingIndex] ?? null;

  const exPriceFor = useMemo(
    () => (gaugeDiff: unknown) =>
      calcVariantExPrice({
        basePrice: pricing.base_price,
        totalCharges: pricing.total_charges,
        gaugeDiff: Number(gaugeDiff ?? 0),
        qualityPrice: selectedQuality?.price ?? 0,
        packagingCharge: selectedPackaging?.charge ?? 0,
        gst: pricing.gst,
      }),
    [pricing, selectedQuality, selectedPackaging]
  );

  /* Basic is the raw product price for the variant — no loading, insurance,
     quality, packaging or GST — and F.O.R adds the freight leg to Ex-Works. */
  const priceFor = useMemo(
    () => (gaugeDiff: unknown) => {
      const ex = exPriceFor(gaugeDiff);
      if (basis === "basic") return pricing.base_price + Number(gaugeDiff ?? 0);
      if (basis === "for") return ex + pricing.freight_charges;
      return ex;
    },
    [basis, exPriceFor, pricing]
  );

  const rows = useMemo(
    () =>
      selectedIds
        .map((id) => sellable.find((variation) => variation.id === id))
        .filter((variation): variation is ApiProductVariation => Boolean(variation))
        .map((variation) => {
          const exPrice = exPriceFor(variation.price);
          const unitPrice = priceFor(variation.price);
          const qty = Number(quantities[variation.id] ?? "") || 0;
          return { variation, exPrice, unitPrice, qty, lineTotal: unitPrice * qty };
        }),
    [selectedIds, sellable, quantities, exPriceFor, priceFor]
  );

  const totalQty = rows.reduce((sum, row) => sum + row.qty, 0);
  const totalSelected = rows.reduce((sum, row) => sum + row.lineTotal, 0);
  const totalEx = rows.reduce((sum, row) => sum + row.exPrice * row.qty, 0);
  const totalFor = totalEx + pricing.freight_charges * totalQty;
  // Live, not only on submit: the buyer sees the MOQ gap while adding sizes (B14).
  const belowMoq = minOrderQty > 0 && rows.length > 0 && totalQty > 0 && totalQty < minOrderQty;

  function removeVariation(id: number) {
    setSelectedIds((prev) => prev.filter((v) => v !== id));
    setQuantities((prev) => {
      const next = { ...prev };
      delete next[id];
      return next;
    });
  }

  function toggleVariation(id: number) {
    setError(null);
    if (selectedIds.includes(id)) {
      removeVariation(id);
      return;
    }
    setSelectedIds((prev) => [...prev, id]);
  }

  function handleSubmit() {
    if (rows.length === 0) {
      setError("Please select at least one variant.");
      return;
    }
    // Same rules as the API: every size a real quantity, the total at least
    // the product's MOQ. The API rejects anything this lets through.
    for (const row of rows) {
      const rowError = quantityError(quantities[row.variation.id] ?? "");
      if (rowError) {
        setError(`${variationLabel(row.variation)}: ${rowError}`);
        return;
      }
    }
    // The live MOQ hint above the button already says why; just don't proceed.
    if (minOrderQty > 0 && totalQty < minOrderQty) return;

    const draftVariations: RfqDraftVariation[] = rows.map((row) => ({
      id: row.variation.id,
      value: row.variation.value,
      price: Number(row.variation.price ?? 0),
      quantity: String(row.qty),
      stock: null,
      user_selected: "true",
      ex_price: row.exPrice,
      line_total: row.lineTotal,
    }));

    setPending(true);
    saveRfqDraft({
      product: { id: productId, slug, name, thumbnail, unit, min_order_qty: minOrderQty },
      brand,
      origin_city: originCity,
      delivery_city: deliveryCity,
      quality: selectedQuality,
      packaging: selectedPackaging,
      price_option: basis,
      variations: draftVariations,
      totals: {
        quantity: totalQty,
        ex_price: totalEx,
        freight_per_unit: pricing.freight_charges,
        for_price: totalFor,
      },
    });
    router.push("/rfq/new");
  }

  if (sellable.length === 0 && quality.length === 0 && packaging.length === 0) {
    return <p className="text-xs text-gray-400">No variants published for this product yet.</p>;
  }

  return (
    <div className="space-y-5">
      {bases.length > 1 && (
        <div>
          <h3 className="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500">
            Price Option
          </h3>
          <div className="flex flex-wrap gap-2">
            {bases.map((option) => (
              <button
                key={option}
                type="button"
                onClick={() => setBasis(option)}
                className={chipClass(basis === option)}
                aria-pressed={basis === option}
                title={PRICE_OPTIONS[option].hint}
              >
                {PRICE_OPTIONS[option].label}
              </button>
            ))}
          </div>
        </div>
      )}

      {quality.length > 0 && (
        <div>
          <h3 className="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500">
            Select Quality
          </h3>
          <div className="flex flex-wrap gap-2">
            {quality.map((option, index) => (
              <button
                key={option.name}
                type="button"
                onClick={() => setQualityIndex(index)}
                className={chipClass(qualityIndex === index)}
              >
                {option.name}
                <span className="text-[10px] text-gray-400">
                  {formatAmount(option.price)}
                </span>
              </button>
            ))}
          </div>
        </div>
      )}

      {packaging.length > 0 && (
        <div>
          <h3 className="mb-2 text-xs font-semibold uppercase tracking-wide text-gray-500">
            Select Packaging
          </h3>
          <div className="flex flex-wrap gap-2">
            {packaging.map((option, index) => (
              <button
                key={option.id}
                type="button"
                onClick={() => setPackagingIndex(index)}
                className={chipClass(packagingIndex === index)}
              >
                {option.name}
                <span className="text-[10px] text-gray-400">{formatAmount(option.charge)}</span>
              </button>
            ))}
          </div>
        </div>
      )}

      {sellable.length > 0 && (
        <div>
          <div className="mb-2 flex flex-wrap items-center justify-between gap-2">
            <h3 className="text-xs font-semibold uppercase tracking-wide text-gray-500">
              Select Variations ({groupLabel})
            </h3>
            {minOrderQty > 0 && (
              <span className="rounded-md bg-gray-100 px-2 py-0.5 text-[11px] font-medium text-gray-600">
                MOQ {minOrderQty} {unit}
              </span>
            )}
          </div>
          <div className="flex flex-wrap gap-2">
            {sellable.map((variation) => {
              const active = selectedIds.includes(variation.id);
              return (
                <button
                  key={variation.id}
                  type="button"
                  onClick={() => toggleVariation(variation.id)}
                  className={chipClass(active)}
                  aria-pressed={active}
                >
                  {active ? <X size={12} /> : <Plus size={12} />}
                  <span>{variationLabel(variation)}</span>
                  {variation.value?.[1] && (
                    <span className="text-[10px] text-gray-400">
                      {valueLabel(variation.value[1])}
                    </span>
                  )}
                </button>
              );
            })}
          </div>
        </div>
      )}

      {rows.length > 0 && (
        <div className="overflow-x-auto">
          <table className="w-full min-w-[520px] text-left text-xs">
            <thead>
              <tr className="border-b border-gray-200 text-gray-500">
                <th className="py-2 pr-3 font-medium">{groupLabel}</th>
                <th className="py-2 pr-3 font-medium">{PRICE_OPTIONS[basis].label} Price</th>
                <th className="py-2 pr-3 font-medium">Quantity ({unit})</th>
                <th className="py-2 pr-3 font-medium">Total</th>
                <th className="py-2 font-medium" />
              </tr>
            </thead>
            <tbody>
              {rows.map(({ variation, unitPrice, lineTotal }) => (
                <tr key={variation.id} className="border-b border-gray-100">
                  <td className="py-2 pr-3 text-gray-900">
                    {variationLabel(variation)}
                    {variation.value?.[1] && (
                      <span className="ml-1 text-[11px] text-gray-400">
                        ({valueLabel(variation.value[1])})
                      </span>
                    )}
                  </td>
                  <td className="py-2 pr-3 text-gray-700">{formatAmount(unitPrice)}</td>
                  <td className="py-2 pr-3">
                    <input
                      type="text"
                      inputMode="decimal"
                      value={quantities[variation.id] ?? ""}
                      onChange={(event) => {
                        setError(null);
                        setQuantities((prev) => ({
                          ...prev,
                          // Digits and one decimal point; "-5" cannot be typed.
                          [variation.id]: event.target.value.replace(/[^\d.]/g, "").replace(/(\..*)\./g, "$1"),
                        }));
                      }}
                      placeholder="Qty"
                      className="w-24 rounded-lg border border-gray-200 px-2 py-1.5 text-xs focus:border-[#CC1414] focus:outline-none"
                    />
                  </td>
                  <td className="py-2 pr-3 font-semibold text-gray-900">
                    {formatAmount(lineTotal)}
                  </td>
                  <td className="py-2">
                    <button
                      type="button"
                      onClick={() => removeVariation(variation.id)}
                      aria-label={`Remove ${variationLabel(variation)}`}
                      className="rounded-md p-1 text-gray-400 transition hover:bg-red-50 hover:text-[#CC1414]"
                    >
                      <X size={14} />
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {rows.length > 0 && (
        <dl className="space-y-1.5 rounded-xl bg-gray-50 p-3 text-xs">
          <div className="flex justify-between">
            <dt className="text-gray-500">
              Total Quantity
            </dt>
            <dd className={`font-medium ${belowMoq ? "text-[#CC1414]" : "text-gray-900"}`}>
              {totalQty} {unit}
            </dd>
          </div>
          {belowMoq && (
            <p role="alert" className="rounded-md bg-red-50 px-2 py-1 text-[11px] font-medium text-[#CC1414]">
              {moqMessage(minOrderQty, formatUnit(unit))} — add {Number((minOrderQty - totalQty).toFixed(2))} {formatUnit(unit)} more.
            </p>
          )}
          <div className="flex justify-between">
            <dt className="text-gray-500">
              {basis === "ex_works" ? "Estimated Ex-Works total" : `Total ${PRICE_OPTIONS[basis].label} Price`}
              {basis === "for" && deliveryCity ? ` (${deliveryCity})` : ""}
              {basis === "basic" && originCity ? ` (${originCity})` : ""}
              {basis === "ex_works" && originCity ? ` (${originCity})` : ""}
            </dt>
            <dd className="font-semibold text-gray-900">{formatAmount(totalSelected)}</dd>
          </div>
          {basis !== "for" && pricing.freight_charges > 0 && (
            <div className="flex justify-between border-t border-gray-200 pt-1.5">
              <dt className="font-semibold text-emerald-600">
                Estimated F.O.R Total{deliveryCity ? ` (${deliveryCity})` : ""}
              </dt>
              <dd className="font-bold text-emerald-600">{formatAmount(totalFor)}</dd>
            </div>
          )}
          <p className="pt-1 text-[11px] leading-relaxed text-gray-400">
            *Ex price = Base Price + Gauge Difference + Loading + Insurance + Quality Charge (if
            applicable) + Packaging + GST. TCS may apply.
          </p>
          <p className="pt-1 text-[11px] font-medium leading-relaxed text-gray-500">
            Price shown is based on the last market update. Final price will be confirmed as per the
            prevailing market rate.
          </p>
        </dl>
      )}

      {error && (
        <p className="rounded-lg bg-red-50 px-3 py-2 text-xs font-medium text-red-700">{error}</p>
      )}

      <button
        type="button"
        onClick={handleSubmit}
        disabled={pending}
        className="inline-flex w-full items-center justify-center gap-2 rounded-lg bg-[#CC1414] px-6 py-2.5 text-sm font-semibold text-white transition hover:bg-[#a30f0f] disabled:opacity-60 sm:w-auto"
      >
        {pending && <Loader2 className="h-4 w-4 animate-spin" />}
        Request For Quotes
      </button>

      {sellable.length > 0 && (
        <details className="rounded-xl border border-gray-100 bg-gray-50 p-3">
          <summary className="cursor-pointer text-xs font-medium text-gray-600">
            View all variations
          </summary>
          <div className="mt-3 overflow-x-auto">
            <table className="w-full min-w-[420px] text-left text-xs">
              <thead>
                <tr className="border-b border-gray-200 text-gray-500">
                  {(sellable[0].value ?? []).map((entry, index) => (
                    <th key={`${entry.name}-${index}`} className="py-1.5 pr-3 font-medium">
                      {entry.name}
                    </th>
                  ))}
                  <th className="py-1.5 font-medium">Gauge Diff.</th>
                </tr>
              </thead>
              <tbody>
                {sellable.map((variation) => (
                  <tr key={variation.id} className="border-b border-gray-100 last:border-0">
                    {(sellable[0].value ?? []).map((_, index) => (
                      <td key={index} className="py-1.5 pr-3 text-gray-700">
                        {valueLabel(variation.value?.[index])}
                      </td>
                    ))}
                    <td className="py-1.5 text-gray-700">
                      {formatAmount(Number(variation.price ?? 0))}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </details>
      )}
    </div>
  );
}
