import { useEffect, useState } from "react";
import { formatCurrency, formatDate } from "@/lib/format";
import type { KolaboraEvent, TicketPhase, TicketType } from "@/types/event";
import type { PricingBreakdown } from "@/types/order";
import { PricingSummary } from "@/components/checkout/pricing-summary";
import type { AppliedPromo, AppliedVoucher } from "./types";

// UI-only ceiling when the phase has neither a quota nor a purchase_limit
// set — not a business rule, just a sane input bound (BR-012's former global
// 3/account cap has been removed; per-ticket identity is now collected in
// StepHolderData so each ticket's holder can be verified).
const NO_LIMIT_FALLBACK = 99;

function maxQuantity(ticketPhase: TicketPhase): number {
  const limits = [NO_LIMIT_FALLBACK];
  if (ticketPhase.quota !== null) limits.push(ticketPhase.quota);
  if (ticketPhase.purchase_limit !== null) limits.push(ticketPhase.purchase_limit);
  return Math.max(0, Math.min(...limits));
}

export function StepTotalOrder({
  event,
  ticketType,
  ticketPhase,
  quantity,
  onQuantityChange,
  promo,
  voucher,
  onApplyPromo,
  onRemovePromo,
  onApplyVoucher,
  onRemoveVoucher,
  quote,
  onQuoteChange,
  onNext,
}: {
  event: KolaboraEvent;
  ticketType: TicketType;
  ticketPhase: TicketPhase;
  quantity: number;
  onQuantityChange: (quantity: number) => void;
  promo: AppliedPromo | null;
  voucher: AppliedVoucher | null;
  onApplyPromo: (promo: AppliedPromo) => void;
  onRemovePromo: () => void;
  onApplyVoucher: (voucher: AppliedVoucher) => void;
  onRemoveVoucher: () => void;
  quote: PricingBreakdown | null;
  onQuoteChange: (quote: PricingBreakdown | null) => void;
  onNext: () => void;
}) {
  const max = maxQuantity(ticketPhase);

  // One shared input for both code types — see handleApplyCode below,
  // which tries promo first and falls back to voucher instead of making
  // the user pick which box to type it into.
  const [codeInput, setCodeInput] = useState("");
  const [codeError, setCodeError] = useState<string | null>(null);
  const [isValidatingCode, setIsValidatingCode] = useState(false);
  const [quoteError, setQuoteError] = useState<string | null>(null);

  function setQuantity(next: number) {
    onQuantityChange(Math.max(1, Math.min(max, next)));
  }

  // The actual subtotal/discount/fee/tax/total — always fetched from the
  // backend (POST /checkout/quote), never recomputed in TS, so this can
  // never disagree with what checkout submission itself charges. Stored in
  // wizard-level state (via onQuoteChange) so StepConfirmation just reads
  // it back instead of recomputing a third time.
  useEffect(() => {
    let cancelled = false;

    fetch("/api/checkout/quote", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        event_id: event.id,
        items: [{ ticket_phase_id: ticketPhase.id, quantity }],
        promo_code: promo?.code ?? null,
        voucher_code: voucher?.code ?? null,
      }),
    })
      .then((res) => res.json().then((body) => ({ ok: res.ok, body })))
      .then(({ ok, body }) => {
        if (cancelled) return;
        if (!ok) {
          setQuoteError(body?.message ?? "Failed to calculate total.");
          onQuoteChange(null);
          return;
        }
        setQuoteError(null);
        onQuoteChange(body.data);
      })
      .catch(() => {
        if (!cancelled) setQuoteError("Unable to reach the server.");
      });

    return () => {
      cancelled = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps -- onQuoteChange is a stable setState wrapper from CheckoutWizard, not a changing value to re-fetch on
  }, [event.id, ticketPhase.id, quantity, promo, voucher]);

  // Tries the code as a promo first; only falls back to validating it as a
  // voucher if the promo lookup itself failed (code not found as a promo
  // at all) — a code that *is* a valid promo but just doesn't apply to
  // this phase/type shows that specific error immediately rather than
  // being masked by a follow-up "not a valid voucher either" message.
  async function handleApplyCode() {
    setCodeError(null);
    setIsValidatingCode(true);

    try {
      const promoRes = await fetch("/api/checkout/validate-promo", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ event_id: event.id, code: codeInput }),
      });
      const promoBody = await promoRes.json().catch(() => null);

      if (promoRes.ok) {
        if (promoBody.data.ticket_phase_id !== null && promoBody.data.ticket_phase_id !== ticketPhase.id) {
          setCodeError("This promo code doesn't apply to this ticket phase.");
          return;
        }
        if (
          promoBody.data.ticket_phase_id === null &&
          promoBody.data.ticket_type_id !== null &&
          promoBody.data.ticket_type_id !== ticketType.id
        ) {
          setCodeError("This promo code doesn't apply to this ticket type.");
          return;
        }

        onApplyPromo({
          code: promoBody.data.code,
          ticket_type_id: promoBody.data.ticket_type_id,
          ticket_phase_id: promoBody.data.ticket_phase_id,
          discount_percentage: promoBody.data.discount_percentage,
        });
        setCodeInput("");
        return;
      }

      const voucherRes = await fetch("/api/checkout/validate-voucher", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ event_id: event.id, code: codeInput }),
      });
      const voucherBody = await voucherRes.json().catch(() => null);

      if (!voucherRes.ok) {
        setCodeError(
          voucherBody?.errors?.voucher_code?.[0] ?? promoBody?.message ?? "Promo/voucher code not found.",
        );
        return;
      }

      if (voucherBody.data.ticket_phase_id !== null && voucherBody.data.ticket_phase_id !== ticketPhase.id) {
        setCodeError("This voucher code doesn't apply to this ticket phase.");
        return;
      }
      if (
        voucherBody.data.ticket_phase_id === null &&
        voucherBody.data.ticket_type_id !== null &&
        voucherBody.data.ticket_type_id !== ticketType.id
      ) {
        setCodeError("This voucher code doesn't apply to this ticket type.");
        return;
      }

      onApplyVoucher({
        code: voucherBody.data.code,
        ticket_type_id: voucherBody.data.ticket_type_id,
        ticket_phase_id: voucherBody.data.ticket_phase_id,
        discount_amount: voucherBody.data.discount_amount,
      });
      setCodeInput("");
    } catch {
      setCodeError("Unable to reach the server. Please try again.");
    } finally {
      setIsValidatingCode(false);
    }
  }

  return (
    <div className="mx-auto max-w-3xl px-6 py-8">
      {/* Event summary banner */}
      <div className="flex items-center gap-4 overflow-hidden rounded-2xl bg-signaturee-cream p-4">
        {event.thumbnail ? (
          // eslint-disable-next-line @next/next/no-img-element -- organizer-uploaded file, not on next/image allowlist
          <img src={event.thumbnail} alt={event.title} className="h-16 w-16 shrink-0 rounded-xl object-cover" />
        ) : (
          <div className="h-16 w-16 shrink-0 rounded-xl bg-neutral-200" />
        )}
        <div className="min-w-0">
          <p className="font-signaturee font-semibold text-signaturee-red">{event.title}</p>
          <p className="text-sm text-neutral-600">
            {formatDate(event.start_date)}
            {event.location ? ` · ${event.location}` : ""}
          </p>
        </div>
      </div>

      <div className="mt-6 grid grid-cols-1 gap-4 sm:grid-cols-2">
        {/* Left: ticket description + quantity */}
        <div className="flex flex-col justify-between rounded-2xl bg-neutral-100 p-6">
          <div>
            <p className="font-signaturee text-lg font-semibold">
              {ticketType.name} &mdash; {ticketPhase.name}
            </p>
            <p className="mt-2 text-sm text-neutral-600">
              Includes event entry for the selected ticket type.
            </p>
          </div>

          <div className="mt-6 flex items-center justify-between">
            <span className="text-sm font-medium text-neutral-600">Quantity</span>
            <div className="flex items-center gap-3">
              <button
                type="button"
                onClick={() => setQuantity(quantity - 1)}
                disabled={quantity <= 1}
                aria-label="Decrease quantity"
                className="flex h-11 w-11 items-center justify-center rounded-full border border-neutral-300 text-lg disabled:opacity-40"
              >
                −
              </button>
              <input
                type="number"
                min={1}
                max={max}
                value={quantity}
                onChange={(e) => setQuantity(Number(e.target.value) || 1)}
                className="h-11 w-14 rounded-lg border border-neutral-300 text-center"
              />
              <button
                type="button"
                onClick={() => setQuantity(quantity + 1)}
                disabled={quantity >= max}
                aria-label="Increase quantity"
                className="flex h-11 w-11 items-center justify-center rounded-full border border-neutral-300 text-lg disabled:opacity-40"
              >
                +
              </button>
            </div>
          </div>
          {ticketPhase.purchase_limit !== null && (
            <p className="mt-2 text-right text-xs text-neutral-500">
              Maximum {ticketPhase.purchase_limit} tickets per account
            </p>
          )}
        </div>

        {/* Right: promo/voucher, subtotal, CTA */}
        <div className="flex flex-col justify-between rounded-2xl bg-neutral-100 p-6">
          <div className="flex flex-col gap-3">
            <p className="text-sm text-neutral-600">Have a promo or voucher code?</p>

            {promo && (
              <div className="flex items-center justify-between rounded-lg border border-signaturee-orange/40 bg-white px-3 py-2 text-xs">
                <span>
                  Promo <span className="font-mono font-medium">{promo.code}</span> &middot; -{promo.discount_percentage}%
                </span>
                <button type="button" onClick={onRemovePromo} className="font-medium text-red-600 hover:underline">
                  Remove
                </button>
              </div>
            )}
            {voucher && (
              <div className="flex items-center justify-between rounded-lg border border-signaturee-orange/40 bg-white px-3 py-2 text-xs">
                <span>
                  Voucher <span className="font-mono font-medium">{voucher.code}</span> &middot; -
                  {formatCurrency(voucher.discount_amount)}
                </span>
                <button type="button" onClick={onRemoveVoucher} className="font-medium text-red-600 hover:underline">
                  Remove
                </button>
              </div>
            )}

            {!promo && !voucher && (
              <div className="flex items-center gap-2">
                <input
                  type="text"
                  value={codeInput}
                  onChange={(e) => setCodeInput(e.target.value.toUpperCase())}
                  placeholder="Promo or voucher code"
                  className="w-full rounded-lg border border-neutral-300 bg-white px-3 py-2 text-sm"
                />
                <button
                  type="button"
                  onClick={handleApplyCode}
                  disabled={isValidatingCode || !codeInput}
                  className="shrink-0 rounded-lg border border-neutral-300 px-3 py-2 text-xs font-medium hover:bg-white disabled:cursor-not-allowed disabled:opacity-50"
                >
                  {isValidatingCode ? "..." : "Apply"}
                </button>
              </div>
            )}
            {codeError && <p className="text-xs text-red-600">{codeError}</p>}
          </div>

          <div className="mt-6">
            {quote && (
              <PricingSummary breakdown={quote} discountLabel={promo ? `Promo ${promo.code}` : `Voucher ${voucher?.code}`} />
            )}
            {quoteError && <p className="mt-2 text-xs text-red-600">{quoteError}</p>}

            <button
              type="button"
              onClick={onNext}
              disabled={quantity < 1 || !quote}
              className="mt-4 w-full rounded-full bg-signaturee-orange px-6 py-3 font-medium text-signaturee-cream hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
            >
              Order Now
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}
