"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import { Search, Wallet, TrendingDown } from "lucide-react";
import { useFormStatus } from "react-dom";
import type { ApiLiveOffer, ApiWalletSummary } from "@/lib/api/types";
import { formatUnit } from "@/lib/utils";
import { acceptQuotation, fetchLiveOffer } from "@/app/(dashboard)/rfq/[id]/actions";
import BiddingStepper from "./BiddingStepper";
import BookingTermsConsent from "./BookingTermsConsent";
import Countdown from "./Countdown";

/** Quotations are shown to the paisa, so this is not `formatCurrency`. */
const inr = new Intl.NumberFormat("en-IN", {
  style: "currency",
  currency: "INR",
  maximumFractionDigits: 2,
});

function money(value: number | null | undefined): string {
  if (value === null || value === undefined || !Number.isFinite(value)) return "—";
  return inr.format(value);
}

/** How often the panel asks the server for a fresher price, in ms. */
const POLL_MS = 6000;

type Props = {
  /** The booking / cancellation rule shown at checkout (4.1). */
  bookingPolicy: string;
  enquiryId: number;
  /** SSR snapshot, so the first paint is already populated. */
  initial: ApiLiveOffer;
  wallet: ApiWalletSummary | null;
};

/**
 * The buyer's whole auction experience: "Finding Best Price" while sellers bid,
 * then "Best Price Found" with the breakup and a way to order.
 *
 * It polls rather than pushes. A websocket would be the right answer for a
 * trading floor, but this is one buyer watching one auction for a few minutes —
 * a 6-second poll that stops the moment the clock runs out costs a handful of
 * requests and needs no new infrastructure.
 *
 * No seller is ever named here, by design: the buyer sees the winning number
 * and its breakup, never who quoted it.
 */
export default function LiveOfferPanel({ enquiryId, initial, wallet, bookingPolicy }: Props) {
  const router = useRouter();
  const [offer, setOffer] = useState<ApiLiveOffer>(initial);
  const [showOrder, setShowOrder] = useState(false);

  // Read inside the interval so the callback identity stays stable and the
  // timer is never torn down and rebuilt on every tick.
  const liveRef = useRef(initial.bidding.is_live);
  liveRef.current = offer.bidding.is_live;

  const refresh = useCallback(async () => {
    const next = await fetchLiveOffer(enquiryId);
    if (next) setOffer(next);
  }, [enquiryId]);

  useEffect(() => {
    if (!initial.bidding.is_live) return;

    const timer = setInterval(() => {
      if (!liveRef.current) {
        clearInterval(timer);
        return;
      }
      void refresh();
    }, POLL_MS);

    return () => clearInterval(timer);
  }, [initial.bidding.is_live, refresh]);

  /*
    The clock hitting zero is a client-side event; the server only learns the
    auction closed when someone asks. One final poll turns "Best Price Found"
    into "Offer Ready" without the buyer having to reload.
  */
  const handleExpire = useCallback(() => {
    void refresh().then(() => router.refresh());
  }, [refresh, router]);

  const best = offer.best_offer;
  const summary = offer.summary;
  const isLive = offer.bidding.is_live;
  const isOrdered = offer.stage === "ordered";
  const unit = formatUnit(summary.unit_label);

  return (
    <div className="space-y-4">
      {/* Progress ------------------------------------------------------- */}
      <div className="rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-100">
        <div className="mb-4 flex flex-wrap items-center justify-between gap-2">
          <div>
            <h2 className="text-base font-semibold text-gray-900">
              {best ? "Best Price Found" : "Finding Best Price"}
            </h2>
            <p className="text-xs text-gray-500">
              {best
                ? "Review the best price and place your order"
                : "We're finding the best price for your requirement"}
            </p>
          </div>

          {isLive ? (
            <span className="inline-flex items-center gap-2 rounded-full bg-red-50 px-3 py-1 text-xs font-semibold text-[#CC1414] ring-1 ring-red-200">
              <span className="h-2 w-2 animate-pulse rounded-full bg-[#CC1414]" />
              LIVE ·{" "}
              <Countdown
                endsAt={offer.bidding.ends_at}
                fallbackSeconds={offer.bidding.seconds_left}
                onExpire={handleExpire}
              />
            </span>
          ) : (
            <span className="rounded-full bg-gray-100 px-3 py-1 text-xs font-semibold text-gray-600">
              {isOrdered ? "Order placed" : "Bidding closed"}
            </span>
          )}
        </div>

        <BiddingStepper stage={offer.stage} />
      </div>

      {/* Waiting state -------------------------------------------------- */}
      {!best && (
        <div className="rounded-xl bg-white p-10 text-center shadow-sm ring-1 ring-gray-100">
          <div className="relative mx-auto flex h-20 w-20 items-center justify-center rounded-full ring-2 ring-gray-100">
            {/* A moving ring, not just a fading icon: the buyer is waiting on a
                live auction and a static badge reads as a stalled page. */}
            {isLive && (
              <span
                aria-hidden
                className="absolute inset-0 animate-spin rounded-full border-2 border-transparent border-t-[#CC1414] border-r-[#CC1414]"
              />
            )}
            <Search className={`h-8 w-8 text-gray-400 ${isLive ? "animate-pulse" : ""}`} />
          </div>
          <p className="mt-4 font-semibold text-gray-900">
            {(offer.quotes_count ?? 0) > 0
              ? `${offer.quotes_count} ${offer.quotes_count === 1 ? "quote" : "quotes"} received`
              : offer.sellers_invited > 0
                ? "RFQ sent to multiple sellers"
                : "Finding sellers for your requirement"}
          </p>
          <p className="mt-1 text-sm text-gray-500">
            {/* Never "no rates" while quotes exist (B27) — they are listed below. */}
            {(offer.quotes_count ?? 0) > 0
              ? "Compare the quotations below and accept the one that suits you."
              : isLive
                ? "Please wait while we get you the best price…"
                : "No rates were received before bidding closed. Our team will reach out to you."}
          </p>
        </div>
      )}

      {/* Best price ----------------------------------------------------- */}
      {best && (
        <div className="rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-100 sm:p-6">
          <div className="rounded-xl bg-emerald-50 p-5 text-center ring-1 ring-emerald-200">
            <p className="text-xs font-medium uppercase tracking-wide text-emerald-800">
              Best F.O.R Price (All Inclusive)
            </p>
            <p className="mt-1 text-3xl font-bold text-emerald-700">
              {money(best.for_price)}
              <span className="text-base font-medium"> / {unit}</span>
            </p>
            {summary.delivery_city && (
              <p className="mt-1 text-sm text-emerald-800">Delivery City: {summary.delivery_city}</p>
            )}
          </div>

          {/* Breakup */}
          <div className="mt-4 rounded-xl ring-1 ring-gray-200">
            <p className="border-b border-gray-100 px-4 py-2.5 text-xs font-semibold uppercase tracking-wide text-gray-500">
              Price Breakup (Per {unit})
            </p>
            <dl className="grid grid-cols-2 gap-y-3 p-4 text-sm sm:grid-cols-4">
              <Cell
                label={`Ex-Works Price${best.ex_works_city ? ` (${best.ex_works_city})` : ""}`}
                value={money(best.ex_works_price)}
              />
              <Cell label="Freight Charges" value={money(best.freight_charges)} />
              <Cell label="Other Charges" value={money(best.other_charges)} />
              <Cell label="F.O.R Price" value={money(best.for_price)} highlight />
            </dl>
          </div>

          {/* Order summary */}
          <div className="mt-4 rounded-xl ring-1 ring-gray-200">
            <p className="border-b border-gray-100 px-4 py-2.5 text-xs font-semibold uppercase tracking-wide text-gray-500">
              Order Summary
            </p>
            <dl className="divide-y divide-gray-100 text-sm">
              <Row label="Product" value={[summary.product, summary.size_label].filter(Boolean).join(" ") || "—"} />
              {summary.brand && <Row label="Brand" value={summary.brand} />}
              <Row
                label="Quantity"
                value={summary.quantity ? `${summary.quantity} ${unit}` : "—"}
              />
              <Row label="Delivery City" value={summary.delivery_city ?? "—"} />
              {summary.required_by && <Row label="Required By" value={summary.required_by} />}
              {best.total_amount !== null && (
                <Row label="Estimated Total" value={money(best.total_amount)} highlight />
              )}
            </dl>
          </div>

          {isLive && (
            <p className="mt-3 flex items-center gap-1.5 text-xs text-gray-500">
              <TrendingDown className="h-3.5 w-3.5 text-emerald-600" />
              Sellers are still bidding — this price may improve until the timer ends.
            </p>
          )}

          {!isOrdered && (
            <div className="mt-5 flex flex-col gap-2 sm:flex-row sm:justify-end">
              <button
                type="button"
                onClick={() => setShowOrder(true)}
                className="rounded-lg bg-[#CC1414] px-5 py-2.5 text-sm font-medium text-white hover:bg-[#a30f0f]"
              >
                Proceed to Order
              </button>
            </div>
          )}
        </div>
      )}

      {showOrder && best && (
        <ProceedToOrderModal
          enquiryId={enquiryId}
          forPrice={best.for_price}
          quantity={summary.quantity}
          unit={unit}
          defaultTotal={best.total_amount ?? best.for_price}
          wallet={wallet}
          bookingPolicy={bookingPolicy}
          onClose={() => setShowOrder(false)}
        />
      )}
    </div>
  );
}

function Cell({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) {
  return (
    <div>
      <dt className="text-[11px] uppercase text-gray-500">{label}</dt>
      <dd className={`mt-0.5 font-medium ${highlight ? "text-emerald-700" : "text-gray-900"}`}>{value}</dd>
    </div>
  );
}

function Row({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) {
  return (
    <div className="flex items-center justify-between gap-3 px-4 py-2.5">
      <dt className="text-gray-500">{label}</dt>
      <dd className={`text-right font-medium ${highlight ? "text-[#CC1414]" : "text-gray-900"}`}>{value}</dd>
    </div>
  );
}

function ConfirmButton({ disabled }: { disabled: boolean }) {
  const { pending } = useFormStatus();

  return (
    <button
      type="submit"
      disabled={pending || disabled}
      className="rounded-lg bg-[#CC1414] px-4 py-2 text-sm font-medium text-white hover:bg-[#a30f0f] disabled:opacity-50"
    >
      {pending ? "Placing order…" : "Confirm Order"}
    </button>
  );
}

/**
 * Confirms the order against whichever bid is winning when the form is
 * submitted — hence `accept_best` rather than a quotation id. The buyer has not
 * been shown a seller and does not need to be.
 */
function ProceedToOrderModal({
  enquiryId,
  forPrice,
  quantity,
  unit,
  defaultTotal,
  wallet,
  bookingPolicy,
  onClose,
}: {
  enquiryId: number;
  forPrice: number;
  quantity: number | null;
  unit: string;
  defaultTotal: number;
  wallet: ApiWalletSummary | null;
  bookingPolicy: string;
  onClose: () => void;
}) {
  const [totalAmount, setTotalAmount] = useState(defaultTotal.toFixed(2));
  const [tokenAmount, setTokenAmount] = useState(String(Math.max(1, Math.round(defaultTotal * 0.1))));
  const [selectedWallet, setSelectedWallet] = useState<"cash_balance" | "credit_balance">("cash_balance");

  const balance =
    selectedWallet === "cash_balance" ? (wallet?.cash_balance ?? 0) : (wallet?.credit_balance ?? 0);
  const short = Number(tokenAmount) > balance;

  return (
    /* items-start + scrollable backdrop: a panel taller than the viewport (iOS
       keyboard open) would otherwise overflow upward and put Confirm out of
       reach. */
    <div className="fixed inset-0 z-[100] flex items-start justify-center overflow-y-auto overscroll-contain bg-black/50 p-4 sm:items-center">
      <form action={acceptQuotation} className="my-auto w-full max-w-md rounded-xl bg-white p-5 shadow-xl sm:p-6">
        <input type="hidden" name="enquiry_id" value={enquiryId} />
        <input type="hidden" name="accept_best" value="1" />
        <input type="hidden" name="selected_wallet" value={selectedWallet} />

        <h3 className="text-lg font-bold text-gray-900">Confirm Order</h3>
        <p className="mt-1 text-sm text-gray-600">
          At the best F.O.R price of <span className="font-medium">{money(forPrice)}</span> / {unit}
          {quantity ? ` for ${quantity} ${unit}` : ""}.
        </p>

        <div className="mt-4 space-y-3">
          <div>
            <label htmlFor="live-total" className="mb-1 block text-sm font-medium text-gray-700">
              Total Order Amount (₹)
            </label>
            <input
              id="live-total"
              type="number"
              name="total_amount"
              value={totalAmount}
              onChange={(e) => setTotalAmount(e.target.value)}
              min={1}
              className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
            />
          </div>
          <div>
            <label htmlFor="live-token" className="mb-1 block text-sm font-medium text-gray-700">
              Token Amount (₹)
            </label>
            <input
              id="live-token"
              type="number"
              name="token_amount"
              value={tokenAmount}
              onChange={(e) => setTokenAmount(e.target.value)}
              min={1}
              className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:border-[#CC1414] focus:outline-none"
            />
          </div>
          <div>
            <span className="mb-1 block text-sm font-medium text-gray-700">Pay From</span>
            <div className="grid grid-cols-2 gap-2">
              {(["cash_balance", "credit_balance"] as const).map((w) => (
                <button
                  key={w}
                  type="button"
                  onClick={() => setSelectedWallet(w)}
                  className={`rounded-lg border p-3 text-left text-xs transition ${
                    selectedWallet === w
                      ? "border-[#CC1414] bg-red-50 text-[#CC1414]"
                      : "border-gray-200 hover:border-gray-300"
                  }`}
                >
                  <span className="flex items-center gap-1 font-medium">
                    <Wallet className="h-3 w-3" /> {w === "cash_balance" ? "Cash" : "Credit"}
                  </span>
                  <span className="mt-1 block font-semibold text-gray-900">
                    {money(w === "cash_balance" ? (wallet?.cash_balance ?? 0) : (wallet?.credit_balance ?? 0))}
                  </span>
                </button>
              ))}
            </div>
            <p className={`mt-1 text-xs ${short ? "text-[#CC1414]" : "text-gray-500"}`}>
              Available: {money(balance)}
              {short ? " — token amount exceeds this balance." : ""}
            </p>
          </div>
        </div>

        <BookingTermsConsent policy={bookingPolicy} />

        <div className="mt-5 flex items-center justify-end gap-2">
          <button
            type="button"
            onClick={onClose}
            className="rounded-lg border border-gray-200 px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50"
          >
            Cancel
          </button>
          <ConfirmButton
            disabled={Number(tokenAmount) <= 0 || Number(totalAmount) <= 0 || short}
          />
        </div>
      </form>
    </div>
  );
}
