"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { formatPrice } from "@/lib/format";
import { MERCHANT } from "@/lib/merchant";
import EventMerchPicker, { merchLines, type EventMerch, type MerchCart } from "./event-merch-picker";
import PaystackMark from "@/components/paystack-mark";
import { MpesaMark, PaypalMark } from "@/components/payment-marks";

type PaymentMethod = "card" | "mpesa" | "paypal";

// What the public event page is allowed to know about a ticket type. Stock
// and sales counts stay on the server (organizers don't want them shown) --
// the page only learns how many it may offer in the Qty picker (capped at
// 10, so a big allocation never shows through) and which tier to badge.
export interface PublicTicketType {
  id: string;
  name: string;
  price_cents: number;
  original_price_cents: number | null;
  currency: string;
  admits_count: number;
  max_per_order: number;
  /** Organizer closed this tier, or its stop-selling time has passed. */
  closed: boolean;
  popular: boolean;
}
type MpesaPhase = "idle" | "pushed" | "paid" | "failed";

// Optional public FX rate (KES per 1 USD) used only to show an estimate next to
// the PayPal option; the server is the source of truth for the actual charge.
const PAYPAL_KES_PER_USD = Number(process.env.NEXT_PUBLIC_PAYPAL_KES_PER_USD);

export default function TicketSelector({
  eventId,
  ticketTypes,
  paymentFailed = false,
  merch = null,
}: {
  eventId: string;
  ticketTypes: PublicTicketType[];
  paymentFailed?: boolean;
  // The organizer's open merch shop, sold in the same checkout as tickets.
  merch?: EventMerch | null;
}) {
  const [quantities, setQuantities] = useState<Record<string, number>>({});
  const [buyer, setBuyer] = useState({ name: "", email: "", phone: "" });
  const [method, setMethod] = useState<PaymentMethod>(paymentFailed ? "card" : "mpesa");
  const [loading, setLoading] = useState(false);
  // Paystack sends a declined/abandoned card payment back with ?payment=failed.
  const [error, setError] = useState<string | null>(
    paymentFailed ? "Your Paystack payment didn't go through and you weren't charged. Try again, or pay with M-Pesa." : null
  );
  const [mpesaPhase, setMpesaPhase] = useState<MpesaPhase>("idle");
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);


  const [couponCode, setCouponCode] = useState("");
  const [couponLoading, setCouponLoading] = useState(false);
  const [couponError, setCouponError] = useState<string | null>(null);
  const [appliedCoupon, setAppliedCoupon] = useState<
    { code: string; discountCents: number; subtotalCents: number; appliesTo: "tickets" | "merch" } | null
  >(null);

  // Merch added to this order (paid in the same payment).
  const [merchCart, setMerchCart] = useState<MerchCart>({});
  const [merchFulfillment, setMerchFulfillment] = useState<"pickup" | "delivery">(
    merch && !merch.shop.pickupEnabled ? "delivery" : "pickup"
  );
  const [merchAddress, setMerchAddress] = useState({ address: "", city: "" });
  const mLines = merch ? merchLines(merch, merchCart) : [];
  const merchSubtotalCents = mLines.reduce((s, l) => s + l.variant.priceCents * l.quantity, 0);
  const merchDeliveryCents = mLines.length && merchFulfillment === "delivery" ? (merch?.shop.deliveryFeeCents ?? 0) : 0;

  const currency = ticketTypes[0]?.currency ?? "usd";

  const subtotalCents = useMemo(
    () =>
      ticketTypes.reduce(
        (sum, tt) => sum + (quantities[tt.id] ?? 0) * tt.price_cents,
        0
      ),
    [quantities, ticketTypes]
  );

  // A coupon's discount was priced off the subtotal at the moment it was
  // applied — if the buyer changes quantities afterward, treat it as stale
  // rather than charging a discount computed against a different total; they
  // can re-apply against the new total.
  const couponStale = appliedCoupon !== null && appliedCoupon.subtotalCents !== subtotalCents + merchSubtotalCents;
  const activeCoupon = couponStale ? null : appliedCoupon;
  const ticketDiscount = activeCoupon?.appliesTo === "tickets" ? activeCoupon.discountCents : 0;
  const merchDiscount = activeCoupon?.appliesTo === "merch" ? activeCoupon.discountCents : 0;

  const ticketTotalCents = Math.max(0, subtotalCents - ticketDiscount);
  const merchTotalCents = mLines.length ? Math.max(0, merchSubtotalCents - merchDiscount) + merchDeliveryCents : 0;
  const totalCents = ticketTotalCents + merchTotalCents;
  const merchPayload = mLines.length
    ? {
        items: mLines.map((l) => ({ variantId: l.variant.id, quantity: l.quantity })),
        fulfillment: merchFulfillment,
        address: merchFulfillment === "delivery" ? merchAddress : null,
      }
    : undefined;

  const hasSelection = Object.values(quantities).some((q) => q > 0);

  useEffect(() => {
    return () => {
      if (pollRef.current) clearInterval(pollRef.current);
    };
  }, []);

  async function handleApplyCoupon() {
    if (!couponCode.trim()) return;
    setCouponLoading(true);
    setCouponError(null);

    const res = await fetch("/api/coupons/validate", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        eventId,
        code: couponCode.trim(),
        items: items(),
        buyerEmail: buyer.email || undefined,
        merchSubtotalCents: merchSubtotalCents || undefined,
      }),
    });
    const data = await res.json();

    if (!res.ok || !data.valid) {
      setCouponError(data.error || "Coupon could not be applied");
      setAppliedCoupon(null);
    } else {
      setAppliedCoupon({
        code: couponCode.trim(),
        discountCents: data.discountCents,
        subtotalCents: subtotalCents + merchSubtotalCents,
        appliesTo: data.appliesTo === "merch" ? "merch" : "tickets",
      });
    }
    setCouponLoading(false);
  }

  function items() {
    return ticketTypes
      .filter((tt) => (quantities[tt.id] ?? 0) > 0)
      .map((tt) => ({ ticketTypeId: tt.id, quantity: quantities[tt.id] }));
  }

  async function handleCardCheckout() {
    setLoading(true);
    setError(null);

    const res = await fetch("/api/paystack/checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ eventId, items: items(), buyer, couponCode: activeCoupon?.code, merch: merchPayload }),
    });
    const data = await res.json();

    if (!res.ok) {
      setError(data.error || "Something went wrong");
      setLoading(false);
      return;
    }

    window.location.href = data.url;
  }

  async function handlePaypalCheckout() {
    setLoading(true);
    setError(null);

    const res = await fetch("/api/paypal/checkout", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ eventId, items: items(), buyer, couponCode: activeCoupon?.code }),
    });
    const data = await res.json();

    if (!res.ok) {
      setError(data.error || "Something went wrong");
      setLoading(false);
      return;
    }

    window.location.href = data.url;
  }

  async function handleMpesaCheckout() {
    setLoading(true);
    setError(null);
    setMpesaPhase("idle");

    const res = await fetch("/api/mpesa/stk", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ eventId, items: items(), buyer, couponCode: activeCoupon?.code, merch: merchPayload }),
    });
    const data = await res.json();

    if (!res.ok) {
      setError(data.error || "Something went wrong");
      setLoading(false);
      return;
    }

    setMpesaPhase("pushed");

    pollRef.current = setInterval(async () => {
      const statusRes = await fetch(`/api/mpesa/status?orderId=${data.orderId}`);
      const statusData = await statusRes.json();
      if (statusData.status === "paid") {
        clearInterval(pollRef.current!);
        window.location.href = `/orders/${data.orderId}/success`;
      } else if (statusData.status === "cancelled") {
        clearInterval(pollRef.current!);
        setMpesaPhase("failed");
        setLoading(false);
      }
    }, 3000);
  }

  if (!ticketTypes.length) {
    return <p className="text-neutral-500 text-sm">No tickets available for this event yet.</p>;
  }

  return (
    <div className="min-w-0 space-y-4">
      <div className="grid sm:grid-cols-2 gap-3">
        {ticketTypes.map((tt) => {
          const soldOut = tt.max_per_order <= 0;
          const isPopular = tt.popular;
          const isVvip = /vvip/i.test(tt.name);
          const qty = quantities[tt.id] ?? 0;
          return (
            <div
              key={tt.id}
              className={`relative rounded-2xl border bg-panel p-5 transition-colors ${
                qty > 0
                  ? "border-brand-green ring-1 ring-brand-green"
                  : isPopular
                  ? "border-brand-green/50"
                  : "border-line"
              }`}
            >
              {isPopular && (
                <span className="absolute -top-2.5 right-4 rounded-full bg-brand-green px-3 py-0.5 text-[10px] font-bold uppercase tracking-wider text-white">
                  Popular
                </span>
              )}
              <p
                className={`font-bold text-lg ${
                  isVvip
                    ? "bg-gradient-to-r from-brand-gold-h to-brand-gold bg-clip-text text-transparent"
                    : "text-white"
                }`}
              >
                {tt.name}
              </p>
              {tt.admits_count > 1 && (
                <p className="mt-0.5 text-xs font-medium text-brand-green-h">
                  Admits {tt.admits_count} people · {tt.admits_count} separate QR tickets
                  {tt.price_cents > 0 &&
                    ` · ${formatPrice(Math.round(tt.price_cents / tt.admits_count), tt.currency)} per person`}
                </p>
              )}
              <p className="mt-1 flex items-baseline gap-2">
                <span
                  className={`text-2xl font-black ${
                    isVvip ? "text-brand-gold-h" : "text-brand-green-h"
                  }`}
                >
                  {tt.price_cents === 0 ? "FREE" : formatPrice(tt.price_cents, tt.currency)}
                </span>
                {tt.original_price_cents !== null &&
                  tt.original_price_cents > tt.price_cents && (
                    <span className="text-sm text-muted line-through">
                      {formatPrice(tt.original_price_cents, tt.currency)}
                    </span>
                  )}
              </p>
              {soldOut && (
                <p className="mt-1 text-xs font-semibold text-muted">{tt.closed ? "Sales closed" : "Sold out"}</p>
              )}
              <div className="mt-4 flex items-center gap-2">
                <span className="text-xs text-muted">Qty</span>
                <select
                  disabled={soldOut}
                  value={qty}
                  onChange={(e) =>
                    setQuantities({ ...quantities, [tt.id]: parseInt(e.target.value, 10) })
                  }
                  className="input w-20"
                >
                  {Array.from({ length: tt.max_per_order + 1 }, (_, i) => i).map((n) => (
                    <option key={n} value={n}>
                      {n}
                    </option>
                  ))}
                </select>
              </div>
            </div>
          );
        })}
      </div>

      {merch && merch.products.length > 0 && (
        <EventMerchPicker merch={merch} cart={merchCart} setCart={setMerchCart} />
      )}
      {mLines.length > 0 && !hasSelection && (
        <p className="text-sm text-muted">
          Pick a ticket above to pay for your merch together with it — or buy merch on its own in the{" "}
          <a href={`/shop/${merch!.shop.slug}`} className="text-brand-green-h hover:underline">
            shop
          </a>
          .
        </p>
      )}

      {hasSelection && (
        <div className="rounded-2xl border border-line bg-panel p-4 space-y-3 text-ink">
          <div>
            <label className="block text-sm font-medium mb-1">Your name</label>
            <input
              required
              value={buyer.name}
              onChange={(e) => setBuyer({ ...buyer, name: e.target.value })}
              className="input"
            />
          </div>
          <div>
            <label className="block text-sm font-medium mb-1">Email</label>
            <input
              required
              type="email"
              value={buyer.email}
              onChange={(e) => setBuyer({ ...buyer, email: e.target.value })}
              className="input"
            />
          </div>
          <div>
            <label className="block text-sm font-medium mb-1">Phone number</label>
            <input
              required
              type="tel"
              placeholder="07xx xxx xxx"
              value={buyer.phone}
              onChange={(e) => setBuyer({ ...buyer, phone: e.target.value })}
              className="input"
            />
          </div>

          <div className="flex gap-2">
            <button
              type="button"
              onClick={() => setMethod("mpesa")}
              className={`flex flex-1 items-center justify-center gap-1.5 rounded-md border py-2 text-sm font-medium ${
                method === "mpesa"
                  ? "border-[#39B54A] bg-[#39B54A]/10 text-[#39B54A]"
                  : "border-line text-muted hover:text-ink"
              }`}
            >
              <MpesaMark className="h-4 w-auto" />
              M-Pesa
            </button>
            <button
              type="button"
              onClick={() => setMethod("card")}
              className={`flex flex-1 items-center justify-center gap-1.5 rounded-md border py-2 text-sm font-medium ${
                method === "card"
                  ? "border-[#00C3F7] bg-[#00C3F7]/10 text-[#00C3F7]"
                  : "border-line text-muted hover:text-ink"
              }`}
            >
              <PaystackMark className="h-3.5 w-3.5" />
              Paystack
            </button>
            <button
              type="button"
              onClick={() => setMethod("paypal")}
              disabled={mLines.length > 0}
              title={mLines.length > 0 ? "Pay for tickets + merch with M-Pesa or Paystack" : undefined}
              className={`flex flex-1 items-center justify-center gap-1.5 rounded-md border py-2 text-sm font-medium disabled:opacity-40 ${
                method === "paypal"
                  ? "border-[#009CDE] bg-[#009CDE]/10 text-[#009CDE]"
                  : "border-line text-muted hover:text-ink"
              }`}
            >
              <PaypalMark className="h-3.5 w-3.5" />
              PayPal
            </button>
          </div>

          {method === "mpesa" && (
            <p className="text-xs text-muted">
              STK push sent to the phone number above — charged to PayBill{" "}
              {MERCHANT.mpesa.paybill}, account {buyer.name.trim() || "your name"} —{" "}
              {MERCHANT.businessName}.
            </p>
          )}

          {method === "card" && (
            <p className="text-xs text-muted">
              Pay with Paystack: Visa or Mastercard, charged in KES. You&apos;ll be taken to Paystack&apos;s
              secure page to pay, then straight back here for your tickets.
            </p>
          )}

          {method === "paypal" && (
            <p className="text-xs text-muted">
              PayPal is charged in US dollars
              {currency.toUpperCase() === "KES" && PAYPAL_KES_PER_USD > 0
                ? ` (≈ $${(totalCents / 100 / PAYPAL_KES_PER_USD).toFixed(2)})`
                : ""}
              . You&apos;ll confirm the exact amount on PayPal.
            </p>
          )}

          {mLines.length > 0 && merch && (
            <div className="space-y-2 rounded-lg border border-line p-3">
              <p className="text-sm font-medium">Your merch</p>
              {merch.shop.pickupEnabled && merch.shop.deliveryEnabled && (
                <div className="flex gap-2">
                  {(["pickup", "delivery"] as const).map((f) => (
                    <button
                      key={f}
                      type="button"
                      onClick={() => setMerchFulfillment(f)}
                      className={`flex-1 rounded-md border py-1.5 text-sm ${
                        merchFulfillment === f ? "border-brand-green bg-brand-green/10 text-brand-green-h" : "border-line text-muted"
                      }`}
                    >
                      {f === "pickup" ? "Collect at the event" : `Deliver (+${formatPrice(merch.shop.deliveryFeeCents, "kes")})`}
                    </button>
                  ))}
                </div>
              )}
              {merchFulfillment === "pickup" && merch.shop.pickupInstructions && (
                <p className="text-xs text-muted">{merch.shop.pickupInstructions}</p>
              )}
              {merchFulfillment === "delivery" && (
                <div className="grid gap-2 sm:grid-cols-2">
                  <input
                    value={merchAddress.address}
                    onChange={(e) => setMerchAddress({ ...merchAddress, address: e.target.value })}
                    placeholder="Delivery address"
                    className="input"
                  />
                  <input
                    value={merchAddress.city}
                    onChange={(e) => setMerchAddress({ ...merchAddress, city: e.target.value })}
                    placeholder="Town / city"
                    className="input"
                  />
                </div>
              )}
              <p className="text-xs text-muted">
                You&apos;ll get a pickup code with your tickets. Merchandise sales are final.
              </p>
            </div>
          )}

          <div>
            <label className="block text-sm font-medium mb-1">Coupon code</label>
            {activeCoupon ? (
              <div className="flex items-center justify-between rounded-md border border-green-500 bg-green-500/10 px-3 py-2 text-sm text-green-400">
                <span>
                  &ldquo;{activeCoupon.code}&rdquo; applied — {formatPrice(activeCoupon.discountCents, currency)}{" "}
                  off
                </span>
                <button
                  type="button"
                  onClick={() => {
                    setAppliedCoupon(null);
                    setCouponCode("");
                  }}
                  className="text-xs font-medium text-muted hover:text-ink"
                >
                  Remove
                </button>
              </div>
            ) : (
              <div className="flex gap-2">
                <input
                  value={couponCode}
                  onChange={(e) => setCouponCode(e.target.value)}
                  placeholder="Enter code"
                  className="input flex-1"
                />
                <button
                  type="button"
                  onClick={handleApplyCoupon}
                  disabled={couponLoading || !couponCode.trim()}
                  className="rounded-md border border-line px-4 text-sm font-medium text-ink hover:bg-white/5 disabled:opacity-50"
                >
                  {couponLoading ? "Checking…" : "Apply"}
                </button>
              </div>
            )}
            {couponError && <p className="mt-1 text-xs text-red-600">{couponError}</p>}
          </div>

          <div className="flex flex-col gap-3 pt-2 sm:flex-row sm:items-center sm:justify-between">
            <span className="font-medium">
              {activeCoupon && (
                <span className="mr-2 text-sm text-muted line-through">
                  {formatPrice(subtotalCents + merchSubtotalCents + merchDeliveryCents, currency)}
                </span>
              )}
              Total: {formatPrice(totalCents, currency)}
              {mLines.length > 0 && (
                <span className="block text-xs font-normal text-muted">
                  Tickets {formatPrice(ticketTotalCents, currency)} + merch {formatPrice(merchTotalCents, currency)}
                </span>
              )}
            </span>
            <button
              onClick={
                method === "mpesa"
                  ? handleMpesaCheckout
                  : method === "paypal"
                  ? handlePaypalCheckout
                  : handleCardCheckout
              }
              disabled={
                loading ||
                !buyer.name ||
                !buyer.email ||
                !buyer.phone ||
                mpesaPhase === "pushed" ||
                (method === "paypal" && mLines.length > 0) ||
                (mLines.length > 0 && merchFulfillment === "delivery" && (!merchAddress.address.trim() || !merchAddress.city.trim()))
              }
              className={`inline-flex w-full items-center justify-center gap-2 whitespace-nowrap rounded-full px-6 py-3 text-sm font-semibold hover:brightness-110 sm:w-auto sm:py-2.5 disabled:opacity-50 ${
                method === "card"
                  ? "bg-[#011B33] text-white ring-1 ring-[#00C3F7]/60"
                  : method === "paypal"
                  ? "bg-[#FFC439] text-[#003087]"
                  : "bg-[#39B54A] text-white"
              }`}
            >
              {!loading && method === "card" && <PaystackMark />}
              {!loading && method === "mpesa" && <MpesaMark className="h-5 w-auto" />}
              {!loading && method === "paypal" && <PaypalMark className="h-4 w-4" color="#003087" />}
              {loading
                ? method === "mpesa"
                  ? "Waiting for confirmation…"
                  : "Redirecting…"
                : method === "mpesa"
                ? "Pay with M-Pesa"
                : method === "paypal"
                ? "Pay with PayPal"
                : "Pay with Paystack"}
            </button>
          </div>

          {mpesaPhase === "pushed" && (
            <p className="text-sm text-green-700">
              Check your phone — enter your M-Pesa PIN to complete payment. This page updates
              automatically once confirmed.
            </p>
          )}
          {mpesaPhase === "failed" && (
            <p className="text-sm text-red-600">
              Payment was not completed. You can try again.
            </p>
          )}

          <p className="text-xs text-muted">
            Tickets are non-refundable unless the event is cancelled or rescheduled.
          </p>

          {error && <p className="text-sm text-red-600">{error}</p>}
        </div>
      )}
    </div>
  );
}
