"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import { Info, Search } from "lucide-react";
import { catalogApi } from "@/lib/api/catalog";
import { customerApi } from "@/lib/api/customer";
import { quantityError } from "@/lib/validation";
import FieldError from "@/components/ui/FieldError";
import type { ApiAddress, ApiProduct, ApiProductUnit } from "@/lib/api/types";
import AddressFormModal from "@/components/addresses/AddressFormModal";
import { formatCity } from "@/lib/utils";

/**
 * How soon the buyer needs the load. Free text on the API so operations can
 * widen this list without a migration.
 */
const REQUIRED_BY = [
  "As soon as possible",
  "Within 3 days",
  "Within 1 week",
  "Within 15 days",
  "Within a month",
];

type Props = {
  token: string;
  /** Units from the catalogue; the first is preselected. */
  units: ApiProductUnit[];  /** Carried from the product page / login redirect so the buyer's selection survives (B15). */
  initial?: { productId?: string; quantity?: string; city?: string };
};

/**
 * Step 1 of the Rate Finder: the five things needed to run an auction.
 *
 * Deliberately shorter than the full RFQ form. The detailed form asks for
 * billing and consignee addresses up front, which is a lot to type before you
 * know whether anyone will even quote — and none of it affects the price. Those
 * are collected at order confirmation instead; all the auction needs is what,
 * how much, and where to.
 *
 * On submit the buyer lands on the RFQ page, which is where steps 2 and 3
 * ("Finding Best Price" / "Best Price Found") live.
 */
export default function RateFinderForm({ token, units, initial }: Props) {
  const router = useRouter();

  const [products, setProducts] = useState<ApiProduct[]>([]);
  const [productSearch, setProductSearch] = useState("");
  const [productId, setProductId] = useState(initial?.productId ?? "");
  const [sizeLabel, setSizeLabel] = useState("");
  const [quantity, setQuantity] = useState(initial?.quantity ?? "");
  const [unitId, setUnitId] = useState<string>(() => (units[0] ? String(units[0].id) : ""));
  const [deliveryCity, setDeliveryCity] = useState(initial?.city ?? "");
  const [deliveryState, setDeliveryState] = useState("");
  const [requiredBy, setRequiredBy] = useState(REQUIRED_BY[0]);

  /* Saved addresses (B26): the Rate Finder had no address step at all, so its
     RFQs — and the orders placed from them — carried no billing or ship-to
     address. Bill-to and ship-to are picked here and travel with the RFQ to
     every seller's bid and on to the order. */
  const [addresses, setAddresses] = useState<ApiAddress[]>([]);
  const [billingId, setBillingId] = useState("");
  const [shipToId, setShipToId] = useState("");
  const [addingAddress, setAddingAddress] = useState<null | "billing" | "shipTo">(null);

  useEffect(() => {
    customerApi
      .addresses(token)
      .then((r) => {
        setAddresses(r.data);
        if (r.data[0]) {
          setBillingId(String(r.data[0].id));
          if (initial?.city) setShipToId(String(r.data[0].id));
          else chooseShipTo(r.data[0]);
        }
      })
      .catch(() => setAddresses([]));
    // Load once per token; chooseShipTo only sets state.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token]);

  function chooseShipTo(address: ApiAddress | undefined) {
    if (!address) return;
    setShipToId(String(address.id));
    // The delivery city is the ship-to address's city — what freight is quoted to.
    setDeliveryCity(formatCity(address.city));
    setDeliveryState(address.state ?? "");
  }

  const [submitting, setSubmitting] = useState(false);
  const [err, setErr] = useState<string | null>(null);

  /*
    Debounced so a fast typist does not fire a request per keystroke, and
    aborted on change so a slow early response cannot land after a fast later
    one and repaint the list with stale matches.
  */
  useEffect(() => {
    const controller = new AbortController();
    const timer = setTimeout(() => {
      catalogApi
        .products({ per_page: 50, search: productSearch || undefined })
        .then((r) => {
          if (!controller.signal.aborted) setProducts(r.data);
        })
        .catch(() => {
          if (!controller.signal.aborted) setProducts([]);
        });
    }, 300);

    return () => {
      controller.abort();
      clearTimeout(timer);
    };
  }, [productSearch]);

  const selectedProduct = useMemo(
    () => products.find((p) => String(p.id) === productId) ?? null,
    [products, productId]
  );

  /**
   * Size options published for the selected product.
   *
   * Products carry their variants under different shapes across the catalogue,
   * so anything unrecognised falls back to a free-text box rather than trapping
   * the buyer behind an empty dropdown.
   */
  const sizeOptions = useMemo(() => {
    const raw = (selectedProduct as unknown as { size?: unknown })?.size;
    if (!Array.isArray(raw)) return [];
    return raw
      .map((entry) => (typeof entry === "string" ? entry : (entry as { value?: string })?.value))
      .filter((v): v is string => typeof v === "string" && v.trim() !== "");
  }, [selectedProduct]);

  const unitLabel = units.find((u) => String(u.id) === unitId)?.short_name ?? "";
  const moq = Number(selectedProduct?.min_order_qty ?? 0);
  const moqUnit = /^(mt|metric ton(ne)?)$/i.test(unitLabel) || !unitLabel ? "MT" : unitLabel;
  // Shown inline as the buyer types, not only after submit (B14).
  const qtyError = quantity.trim() ? quantityError(quantity, moq, moqUnit) : null;

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();

    if (!productId) return setErr("Please select a product.");
    if (!sizeLabel.trim()) return setErr("Please enter the thickness or size you need.");
    const qtyMessage = quantityError(quantity, moq, moqUnit);
    if (qtyMessage) return setErr(qtyMessage);
    if (!deliveryCity.trim()) return setErr("Please enter the delivery city.");
    const billing = addresses.find((a) => String(a.id) === billingId);
    const shipTo = addresses.find((a) => String(a.id) === shipToId);
    if (!billing || !shipTo) return setErr("Please choose the billing and delivery address (or add one).");

    setErr(null);
    setSubmitting(true);

    try {
      const r = await customerApi.createEnquiry(token, {
        commodity_product_id: Number(productId),
        size_label: sizeLabel.trim(),
        quantity: Number(quantity),
        unit_id: unitId ? Number(unitId) : null,
        unit_label: unitLabel || null,
        delivery_city: deliveryCity.trim(),
        delivery_state: deliveryState || null,
        billing_address: billing,
        consignee_detail: shipTo,
        required_by: requiredBy,
      });

      // The RFQ page is where the auction is watched — bidding is already open
      // by the time this resolves.
      router.push(`/rfq/${r.data.id}`);
    } catch (e) {
      setErr(e instanceof Error ? e.message : "Could not create your RFQ. Please try again.");
      setSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-100 sm:p-6">
      <div className="mb-4">
        <h2 className="text-base font-semibold text-gray-900">1. What you need</h2>
        <p className="text-xs text-gray-500">Verified sellers bid live for your doorstep price</p>
      </div>

      <div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
        {/* Product */}
        <div className="sm:col-span-2">
          <label htmlFor="rf-product-search" className="mb-1 block text-sm font-medium text-gray-700">
            Product <span className="text-[#CC1414]">*</span>
          </label>
          <div className="relative mb-2">
            <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400" />
            <input
              id="rf-product-search"
              type="text"
              value={productSearch}
              onChange={(e) => setProductSearch(e.target.value)}
              placeholder="Search product… e.g. TMT, angle, saria"
              className="w-full rounded-lg border border-gray-200 py-2 pl-9 pr-3 text-sm focus:border-[#CC1414] focus:outline-none"
            />
          </div>
          <select
            aria-label="Product"
            value={productId}
            onChange={(e) => {
              setProductId(e.target.value);
              setSizeLabel("");
            }}
            required
            className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
          >
            <option value="">Select a product…</option>
            {products.map((p) => (
              <option key={p.id} value={p.id}>
                {p.name}
                {p.category?.name ? ` — ${p.category.name}` : ""}
              </option>
            ))}
          </select>
        </div>

        {/* Size */}
        <div>
          <label htmlFor="rf-size" className="mb-1 block text-sm font-medium text-gray-700">
            Size / Thickness <span className="text-[#CC1414]">*</span>
          </label>
          {sizeOptions.length > 0 ? (
            <select
              id="rf-size"
              value={sizeLabel}
              onChange={(e) => setSizeLabel(e.target.value)}
              required
              className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
            >
              <option value="">Select…</option>
              {sizeOptions.map((s) => (
                <option key={s} value={s}>
                  {s}
                </option>
              ))}
            </select>
          ) : (
            <input
              id="rf-size"
              type="text"
              value={sizeLabel}
              onChange={(e) => setSizeLabel(e.target.value)}
              required
              placeholder="e.g. 12 mm, 50×50×5"
              className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
            />
          )}
        </div>

        {/* Delivery city */}
        <div>
          <label htmlFor="rf-city" className="mb-1 block text-sm font-medium text-gray-700">
            Delivery City <span className="text-[#CC1414]">*</span>
          </label>
          <input
            id="rf-city"
            type="text"
            value={deliveryCity}
            onChange={(e) => setDeliveryCity(e.target.value)}
            required
            placeholder="e.g. Varanasi"
            className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
          />
          <p className="mt-1 text-xs text-gray-500">Only the city is visible to sellers.</p>
        </div>

        {/* Quantity + unit */}
        <div>
          <label htmlFor="rf-qty" className="mb-1 block text-sm font-medium text-gray-700">
            Quantity <span className="text-[#CC1414]">*</span>
          </label>
          <div className="flex gap-2">
            <input
              id="rf-qty"
              type="text"
              inputMode="decimal"
              value={quantity}
              onChange={(e) => setQuantity(e.target.value.replace(/[^\d.]/g, "").replace(/(\..*)\./g, "$1"))}
              required
              placeholder={moq > 0 ? String(moq) : "30"}
              aria-invalid={!!qtyError}
              aria-describedby="rf-qty-err"
              className={`w-full rounded-lg border px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none ${qtyError ? "border-[#CC1414]" : "border-gray-200"}`}
            />
            <select
              aria-label="Unit"
              value={unitId}
              onChange={(e) => setUnitId(e.target.value)}
              className="w-32 shrink-0 rounded-lg border border-gray-200 bg-white px-2 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
            >
              {units.map((u) => (
                <option key={u.id} value={u.id}>
                  {u.short_name || u.name}
                </option>
              ))}
            </select>
          </div>
          {qtyError ? (
            <FieldError id="rf-qty-err" message={qtyError} />
          ) : moq > 0 ? (
            <p className="mt-1 text-xs text-gray-500">Minimum order: {moq} {moqUnit}</p>
          ) : null}
        </div>

        {/* Required by */}
        <div>
          <label htmlFor="rf-required" className="mb-1 block text-sm font-medium text-gray-700">
            Required By
          </label>
          <select
            id="rf-required"
            value={requiredBy}
            onChange={(e) => setRequiredBy(e.target.value)}
            className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
          >
            {REQUIRED_BY.map((option) => (
              <option key={option} value={option}>
                {option}
              </option>
            ))}
          </select>
        </div>
      </div>

      {/* Bill to / ship to from the saved address book (B26) */}
      <div className="mt-4 grid grid-cols-1 gap-4 sm:grid-cols-2">
        {([
          ["billing", "Billing address (Bill to)", billingId, (a: ApiAddress) => setBillingId(String(a.id))],
          ["shipTo", "Delivery address (Ship to)", shipToId, chooseShipTo],
        ] as const).map(([key, label, selected, choose]) => (
          <div key={key}>
            <div className="mb-1 flex items-center justify-between">
              <label htmlFor={`rf-${key}`} className="text-sm font-medium text-gray-700">
                {label} <span className="text-[#CC1414]">*</span>
              </label>
              <button type="button" onClick={() => setAddingAddress(key)} className="text-xs font-semibold text-[#CC1414] hover:underline">
                + Add new
              </button>
            </div>
            {addresses.length > 0 ? (
              <select
                id={`rf-${key}`}
                value={selected}
                onChange={(e) => choose(addresses.find((a) => String(a.id) === e.target.value)!)}
                className="w-full rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
              >
                {addresses.map((a) => (
                  <option key={a.id} value={String(a.id)}>
                    {[a.company_name, a.address_line_one, formatCity(a.city), a.pincode].filter(Boolean).join(", ")}
                  </option>
                ))}
              </select>
            ) : (
              <p className="rounded-lg border border-dashed border-gray-200 px-3 py-2 text-xs text-gray-500">
                No saved address yet — use “+ Add new”.
              </p>
            )}
          </div>
        ))}
      </div>

      <div className="mt-4 flex items-start gap-2 rounded-lg bg-blue-50 p-3 text-xs text-blue-800 ring-1 ring-blue-100">
        <Info className="mt-0.5 h-4 w-4 shrink-0" />
        <p>
          Biznie will run a live auction across multiple sellers and bring you the best all-inclusive
          F.O.R (doorstep) price. Sellers see only the delivery city until you confirm the order.
        </p>
      </div>

      {addingAddress && (
        <AddressFormModal
          token={token}
          onClose={() => setAddingAddress(null)}
          onSaved={(address) => {
            setAddresses((list) => [address, ...list]);
            if (addingAddress === "billing" || !billingId) setBillingId(String(address.id));
            if (addingAddress === "shipTo" || !shipToId) chooseShipTo(address);
            setAddingAddress(null);
          }}
        />
      )}

      {err && (
        <p role="alert" className="mt-3 rounded-lg bg-red-50 p-3 text-sm text-red-700 ring-1 ring-red-100">
          {err}
        </p>
      )}

      <div className="mt-5 flex justify-end">
        <button
          type="submit"
          disabled={submitting}
          className="w-full rounded-lg bg-[#CC1414] px-6 py-2.5 text-sm font-medium text-white hover:bg-[#a30f0f] disabled:opacity-50 sm:w-auto"
        >
          {submitting ? "Starting auction…" : "Continue"}
        </button>
      </div>
    </form>
  );
}
