import { useEffect, useState } from "react";
import { loadStripe, Stripe } from "@stripe/stripe-js";
import { Elements, PaymentElement, useStripe, useElements } from "@stripe/react-stripe-js";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Loader2, CheckCircle2, AlertCircle, Gift } from "lucide-react";
import { toast } from "sonner";
import { useAuth } from "@/hooks/useAuth";
import { router } from "@inertiajs/react";
import { CartItem } from "@/contexts/CartContext";
import { getReferralCode, clearReferralCode } from "@/lib/referral";
import { vatCents, grossCents } from "@/lib/vat";
import InlineSignIn from "@/components/InlineSignIn";

const csrfToken = () =>
  (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement | null)?.content ?? '';

interface CartCheckoutModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  items: CartItem[];
  /** Optional company id for the logged-in user's company account (enables Pay-on-Invoice). */
  companyId?: string | null;
  /** Called after successful checkout so the cart can clear itself before redirect. */
  onCompleted?: (orderIds: string[]) => void;
}

type Step = "auth-required" | "details" | "payment" | "error";

const PaymentForm = ({
  onSuccess,
  onError,
  amount,
}: {
  onSuccess: () => void;
  onError: (msg: string) => void;
  amount: number;
}) => {
  const stripe = useStripe();
  const elements = useElements();
  const [processing, setProcessing] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!stripe || !elements) return;
    setProcessing(true);
    try {
      const { error, paymentIntent } = await stripe.confirmPayment({
        elements,
        confirmParams: { return_url: window.location.href },
        redirect: "if_required",
      });
      if (error) onError(error.message || "Payment failed");
      else if (paymentIntent?.status === "succeeded") onSuccess();
      else onError("Payment was not completed. Please try again.");
    } catch (err: any) {
      onError(err.message || "An unexpected error occurred");
    } finally {
      setProcessing(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-6">
      <PaymentElement options={{ layout: "tabs" }} />
      <div className="border-t border-border pt-4">
        <div className="flex justify-between text-sm mb-4">
          <span className="text-muted-foreground">Total</span>
          <span className="font-bold text-foreground">£{(amount / 100).toFixed(2)}</span>
        </div>
        <Button type="submit" variant="hero" size="lg" className="w-full" disabled={!stripe || processing}>
          {processing ? (
            <><Loader2 className="w-4 h-4 animate-spin mr-2" />Processing…</>
          ) : (
            `Pay £${(amount / 100).toFixed(2)}`
          )}
        </Button>
      </div>
    </form>
  );
};

const CartCheckoutModal = ({ open, onOpenChange, items, companyId, onCompleted }: CartCheckoutModalProps) => {
  const { user } = useAuth();

  const [step, setStep] = useState<Step>("details");
  const [customerName, setCustomerName] = useState("");
  const [customerEmail, setCustomerEmail] = useState("");
  const [customerPhone, setCustomerPhone] = useState("");
  const [paymentMethod, setPaymentMethod] = useState<"stripe" | "invoice">("stripe");
  const [loading, setLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState("");

  // Stripe state
  const [stripePromise, setStripePromise] = useState<Promise<Stripe | null> | null>(null);
  const [clientSecret, setClientSecret] = useState<string | null>(null);
  const [orderIds, setOrderIds] = useState<string[]>([]);
  const [totalAmount, setTotalAmount] = useState(0);

  // Company credit info
  const [companyCreditLimitCents, setCompanyCreditLimitCents] = useState(0);
  const [companyCreditAvailableCents, setCompanyCreditAvailableCents] = useState(0);
  const [companyPaymentTermsDays, setCompanyPaymentTermsDays] = useState(30);

  // Credit notes the holder can spend at this checkout
  interface ApplicableCreditNote {
    id: string;
    reference: string;
    balance_cents: number;
    amount_cents: number;
    expires_at: string | null;
  }
  const [applicableCreditNotes, setApplicableCreditNotes] = useState<ApplicableCreditNote[]>([]);
  const [selectedCreditNoteIds, setSelectedCreditNoteIds] = useState<Set<string>>(new Set());

  // Referral code captured from a ?ref=... share link, validated when modal opens
  const [referralCode, setReferralCodeState] = useState<string | null>(null);
  const [referralReferrerName, setReferralReferrerName] = useState<string | null>(null);

  useEffect(() => {
    if (!open) return;
    const stored = getReferralCode();
    if (!stored) { setReferralCodeState(null); setReferralReferrerName(null); return; }
    let cancelled = false;
    (async () => {
      try {
        const res = await fetch('/api/functions/validate-referral-code', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
          body: JSON.stringify({ code: stored }),
        });
        const data = await res.json();
        if (cancelled) return;
        if (data?.is_valid) {
          setReferralCodeState(stored);
          setReferralReferrerName(data.referrer_name || null);
        } else {
          clearReferralCode();
          setReferralCodeState(null);
          setReferralReferrerName(null);
        }
      } catch {
        if (!cancelled) { setReferralCodeState(null); setReferralReferrerName(null); }
      }
    })();
    return () => { cancelled = true; };
  }, [open]);

  useEffect(() => {
    if (user) {
      setCustomerEmail((user as any).email || "");
      setCustomerName((user as any).name || (user as any).user_metadata?.full_name || "");
      // Pre-fill the booker's phone from their account (individual: own phone;
      // company manager: the company's contact number — see User::contactPhone()).
      setCustomerPhone((user as any).phone || "");
    }
  }, [user]);

  useEffect(() => {
    if (open) setStep(user ? "details" : "auth-required");
  }, [open, user]);

  useEffect(() => {
    if (!companyId) return;
    (async () => {
      try {
        const res = await fetch(`/api/training-companies/${companyId}/credit`);
        if (!res.ok) return;
        const data = await res.json();
        if (data) {
          setCompanyCreditLimitCents(data.credit_limit_cents ?? 0);
          setCompanyCreditAvailableCents(data.credit_available_cents ?? 0);
          setCompanyPaymentTermsDays(data.payment_terms_days ?? 30);
        }
      } catch {
        // ignore
      }
    })();
  }, [companyId]);

  useEffect(() => {
    if (!open || !user) return;
    const params = new URLSearchParams();
    if (companyId) params.set('company_id', companyId);
    (async () => {
      try {
        const res = await fetch(`/api/credit-notes/applicable?${params.toString()}`);
        if (!res.ok) return;
        const data = await res.json();
        setApplicableCreditNotes(Array.isArray(data) ? data : []);
      } catch {
        setApplicableCreditNotes([]);
      }
    })();
  }, [open, user, companyId]);

  const subtotalCents = items.reduce((sum, i) => sum + i.priceCents * i.numDelegates, 0);
  // Referral discount — 15% off subtotal when a valid referral is captured.
  const referralDiscountCents = referralCode ? Math.round(subtotalCents * 0.15) : 0;
  const afterReferralCents = Math.max(0, subtotalCents - referralDiscountCents);
  const selectedNotes = applicableCreditNotes.filter((n) => selectedCreditNoteIds.has(n.id));
  const rawCreditApplied = selectedNotes.reduce((s, n) => s + n.balance_cents, 0);
  const creditNoteAmountCents = Math.min(rawCreditApplied, afterReferralCents);
  const totalCents = Math.max(0, afterReferralCents - creditNoteAmountCents);
  const hasCompanyCreditAccount = !!companyId && companyCreditLimitCents > 0;
  const canPayOnInvoice = hasCompanyCreditAccount && companyCreditAvailableCents >= grossCents(totalCents);

  const buildCreditNoteRedemptions = () => {
    if (creditNoteAmountCents <= 0 || selectedNotes.length === 0) return [];
    let remaining = creditNoteAmountCents;
    return selectedNotes
      .map((n) => {
        const take = Math.min(n.balance_cents, remaining);
        remaining -= take;
        return { id: n.id, amount_cents: take };
      })
      .filter((r) => r.amount_cents > 0);
  };

  const toggleCreditNote = (id: string) => {
    setSelectedCreditNoteIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const buildItemsPayload = () =>
    items.map((it) => ({
      course_id: it.courseId,
      start_date: it.startDate,
      venue_id: it.venueId || null,
      trainer_id: it.trainerId || null,
      num_delegates: it.numDelegates,
      delegates: it.delegates.map((d) => ({
        first_name: d.first_name.trim(),
        last_name: d.last_name.trim(),
        email: d.email.trim() || null,
        phone: d.phone.trim() || null,
      })),
    }));

  const handleProceed = async () => {
    if (!customerName.trim() || !customerEmail.trim()) {
      toast.error("Please fill in your name and email");
      return;
    }

    // Validate every delegate is filled
    for (const item of items) {
      for (let i = 0; i < item.delegates.length; i++) {
        const d = item.delegates[i];
        if (!d.first_name.trim() || !d.last_name.trim()) {
          toast.error(`Please complete delegate ${i + 1} for "${item.courseTitle}"`);
          return;
        }
        // Email is required for company bookings — used to provision login.
        if (companyId && !d.email.trim()) {
          toast.error(`Delegate ${i + 1} on "${item.courseTitle}" needs an email — required for company bookings.`);
          return;
        }
      }
    }

    // Capacity validation per item
    for (const item of items) {
      try {
        const res = await fetch('/api/functions/check-resource-capacity', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
          body: JSON.stringify({
            course_id: item.courseId,
            start_date: item.startDate,
            num_delegates: item.numDelegates,
          }),
        });
        if (res.ok) {
          const data = await res.json();
          if (data?.error) {
            toast.error(`${item.courseTitle}: ${data.error}`);
            return;
          }
        }
      } catch (err) {
        console.error("Capacity check failed:", err);
      }
    }

    if (paymentMethod === "invoice" && canPayOnInvoice) {
      // Server-side bulk invoice checkout
      setLoading(true);
      try {
        const res = await fetch('/api/functions/complete-bulk-order', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
          body: JSON.stringify({
            payment_method: "invoice",
            company_id: companyId || null,
            customer_name: customerName.trim(),
            customer_email: customerEmail.trim(),
            customer_phone: customerPhone.trim() || null,
            user_id: (user as any)?.id,
            items: buildItemsPayload(),
            referral_code: referralCode,
            credit_note_redemptions: buildCreditNoteRedemptions(),
          }),
        });
        const data = res.ok ? await res.json() : null;
        if (!res.ok) throw new Error(data?.error || "Failed to create orders");
        const ids: string[] = data.order_ids || [];
        if (referralCode) clearReferralCode();
        // Fire-and-forget: confirmation emails & TD-02 links per order
        ids.forEach((oid) => {
          fetch('/api/functions/send-pre-course-form', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
            body: JSON.stringify({ action: "send_link", order_id: oid }),
          }).catch(console.error);
          fetch('/api/functions/send-order-confirmation', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
            body: JSON.stringify({ order_id: oid }),
          }).catch(console.error);
        });
        onCompleted?.(ids);
        onOpenChange(false);
        router.visit(`/checkout/success?order_ids=${encodeURIComponent(ids.join(','))}`);
      } catch (err: any) {
        setErrorMsg(err.message || "Failed to create orders");
        setStep("error");
      } finally {
        setLoading(false);
      }
      return;
    }

    // Stripe bulk checkout
    setLoading(true);
    setErrorMsg("");
    try {
      const res = await fetch('/api/functions/create-bulk-payment-intent', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Accept': 'application/json',
          'X-Requested-With': 'XMLHttpRequest',
          'X-CSRF-TOKEN': csrfToken(),
        },
        body: JSON.stringify({
          company_id: companyId || null,
          customer_name: customerName.trim(),
          customer_email: customerEmail.trim(),
          customer_phone: customerPhone.trim() || null,
          user_id: (user as any)?.id,
          items: buildItemsPayload(),
          referral_code: referralCode,
          credit_note_redemptions: buildCreditNoteRedemptions(),
        }),
      });
      const ct = res.headers.get('content-type') || '';
      const data = ct.includes('application/json') ? await res.json() : null;
      if (!res.ok) throw new Error(data?.error || `Payment setup failed (${res.status})`);
      if (data?.error) throw new Error(data.error);
      if (referralCode) clearReferralCode();

      // Credit covered the full cart — orders are paid; skip Stripe.
      if (data?.fully_covered_by_credit && Array.isArray(data?.orderIds)) {
        const ids = data.orderIds as string[];
        ids.forEach((oid) => {
          fetch('/api/functions/send-order-confirmation', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
            body: JSON.stringify({ order_id: oid }),
          }).catch(console.error);
        });
        onCompleted?.(ids);
        onOpenChange(false);
        router.visit(`/checkout/success?order_ids=${encodeURIComponent(ids.join(','))}`);
        return;
      }

      const { clientSecret: cs, publishableKey, orderIds: ids, amount } = data;
      if (!cs || !publishableKey) {
        throw new Error("Stripe is not configured for this site. Please contact the administrator.");
      }
      setClientSecret(cs);
      setOrderIds(ids || []);
      setTotalAmount(amount);
      setStripePromise(loadStripe(publishableKey));
      setStep("payment");
    } catch (err: any) {
      setErrorMsg(err.message || "Failed to initialize payment");
      setStep("error");
    } finally {
      setLoading(false);
    }
  };

  const handlePaymentSuccess = async () => {
    try {
      await fetch('/api/functions/payment-webhook', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({
          order_ids: orderIds,
          payment_intent_id: clientSecret?.split("_secret_")[0],
        }),
      });
    } catch {
      // The Stripe webhook is the authoritative confirmation; this is a best-effort fallback.
    }
    orderIds.forEach((oid) => {
      fetch('/api/functions/send-order-confirmation', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken() },
        body: JSON.stringify({ order_id: oid }),
      }).catch(console.error);
    });
    onCompleted?.(orderIds);
    onOpenChange(false);
    router.visit(`/checkout/success?order_ids=${encodeURIComponent(orderIds.join(','))}`);
  };

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-lg max-h-[90vh] overflow-y-auto">
        <DialogHeader>
          <DialogTitle>
            {step === "auth-required" && "Account Required"}
            {step === "details" && `Checkout — ${items.length} course${items.length > 1 ? 's' : ''}`}
            {step === "payment" && "Payment"}
            {step === "error" && "Something Went Wrong"}
          </DialogTitle>
        </DialogHeader>

        {step === "auth-required" && (
          <InlineSignIn onCreateAccount={() => onOpenChange(false)} />
        )}

        {step === "details" && (
          <div className="space-y-5">
            <div className="bg-muted/50 rounded-lg p-4 space-y-2 text-sm">
              <div className="font-semibold text-foreground">Order Summary</div>
              <div className="space-y-1 text-xs">
                {items.map((i) => (
                  <div key={i.id} className="flex justify-between">
                    <span className="text-muted-foreground truncate max-w-[260px]">
                      {i.courseTitle} × {i.numDelegates}
                    </span>
                    <span className="font-medium">£{((i.priceCents * i.numDelegates) / 100).toFixed(2)}</span>
                  </div>
                ))}
              </div>
              <div className="border-t border-border pt-2 space-y-1">
                <div className="flex justify-between text-xs text-muted-foreground">
                  <span>Subtotal (ex VAT)</span>
                  <span>£{(subtotalCents / 100).toFixed(2)}</span>
                </div>
                {referralDiscountCents > 0 && (
                  <div className="flex justify-between text-xs text-primary">
                    <span>Referral discount (15% off)</span>
                    <span>-£{(referralDiscountCents / 100).toFixed(2)}</span>
                  </div>
                )}
                {creditNoteAmountCents > 0 && (
                  <div className="flex justify-between text-xs text-blue-500">
                    <span>Credit Note Applied</span>
                    <span>-£{(creditNoteAmountCents / 100).toFixed(2)}</span>
                  </div>
                )}
                <div className="flex justify-between text-xs text-muted-foreground">
                  <span>VAT (20%)</span>
                  <span>£{(vatCents(totalCents) / 100).toFixed(2)}</span>
                </div>
                <div className="flex justify-between font-semibold pt-1 border-t border-border">
                  <span>Total (incl. VAT)</span>
                  <span>£{(grossCents(totalCents) / 100).toFixed(2)}</span>
                </div>
              </div>
            </div>

            {applicableCreditNotes.length > 0 && (
              <div className="space-y-2">
                <Label className="text-sm font-semibold">Apply Credit Note</Label>
                <div className="space-y-1.5">
                  {applicableCreditNotes.map((n) => {
                    const checked = selectedCreditNoteIds.has(n.id);
                    return (
                      <label
                        key={n.id}
                        className={`flex items-center justify-between gap-2 rounded-lg border px-3 py-2 cursor-pointer text-sm ${
                          checked ? 'border-primary bg-primary/5' : 'border-border'
                        }`}
                      >
                        <div className="flex items-center gap-2 min-w-0">
                          <input
                            type="checkbox"
                            checked={checked}
                            onChange={() => toggleCreditNote(n.id)}
                            className="rounded"
                          />
                          <span className="font-mono text-xs text-muted-foreground">{n.reference}</span>
                        </div>
                        <span className="font-semibold whitespace-nowrap">£{(n.balance_cents / 100).toFixed(2)}</span>
                      </label>
                    );
                  })}
                </div>
              </div>
            )}

            <div className="space-y-3">
              <div>
                <Label htmlFor="cart-name">Full Name *</Label>
                <Input id="cart-name" value={customerName} onChange={(e) => setCustomerName(e.target.value)} placeholder="John Smith" />
              </div>
              <div>
                <Label htmlFor="cart-email">Email *</Label>
                <Input id="cart-email" type="email" value={customerEmail} onChange={(e) => setCustomerEmail(e.target.value)} placeholder="john@company.co.uk" />
              </div>
              <div>
                <Label htmlFor="cart-phone">Phone</Label>
                <Input id="cart-phone" type="tel" value={customerPhone} onChange={(e) => setCustomerPhone(e.target.value)} placeholder="07700 900000" />
              </div>
            </div>

            {referralCode && (
              <div className="border-t border-border pt-4">
                <div className="flex items-center gap-2 bg-primary/10 border border-primary/30 rounded-lg p-3">
                  <Gift className="w-4 h-4 text-primary" />
                  <span className="text-sm flex-1">
                    <span className="font-medium text-primary">Referral applied — 15% off</span>
                    {referralReferrerName && (
                      <span className="text-muted-foreground"> · referred by {referralReferrerName}</span>
                    )}
                  </span>
                </div>
              </div>
            )}

            {hasCompanyCreditAccount && (
              <div className="border-t border-border pt-4 space-y-2">
                <Label className="text-sm font-semibold">Payment Method</Label>
                <div className="flex gap-3">
                  <Button
                    variant={paymentMethod === "stripe" ? "default" : "outline"}
                    size="sm"
                    onClick={() => setPaymentMethod("stripe")}
                  >
                    Card Payment
                  </Button>
                  <Button
                    variant={paymentMethod === "invoice" ? "default" : "outline"}
                    size="sm"
                    onClick={() => setPaymentMethod("invoice")}
                    disabled={!canPayOnInvoice}
                    title={!canPayOnInvoice ? "Insufficient available balance for an invoice" : ""}
                  >
                    Pay on Invoice
                  </Button>
                </div>
                <div className="text-xs text-muted-foreground space-y-0.5">
                  <p>
                    Available balance: £{(companyCreditAvailableCents / 100).toFixed(2)}
                    <span className="text-muted-foreground/70"> of £{(companyCreditLimitCents / 100).toFixed(2)} limit</span>
                  </p>
                  {paymentMethod === "invoice" && canPayOnInvoice && (
                    <p>
                      Invoice will be issued — payment terms {companyPaymentTermsDays} days. This cart reserves £{(grossCents(totalCents) / 100).toFixed(2)} (incl. VAT) of your available balance until the invoice is settled.
                    </p>
                  )}
                  {!canPayOnInvoice && (
                    <p>Insufficient available balance for an invoice. Use card payment or contact your administrator.</p>
                  )}
                </div>
              </div>
            )}

            <div className="border-t border-border pt-4 flex justify-between items-center">
              <Button variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
              <Button variant="hero" onClick={handleProceed} disabled={loading}>
                {loading ? (
                  <><Loader2 className="w-4 h-4 animate-spin mr-2" />Processing…</>
                ) : totalCents === 0 ? (
                  "Confirm Booking — FREE"
                ) : paymentMethod === "invoice" ? (
                  `Book on Invoice — £${(grossCents(totalCents) / 100).toFixed(2)}`
                ) : (
                  `Proceed to Payment — £${(grossCents(totalCents) / 100).toFixed(2)}`
                )}
              </Button>
            </div>
          </div>
        )}

        {step === "payment" && clientSecret && stripePromise && (
          <Elements
            stripe={stripePromise}
            options={{
              clientSecret,
              appearance: { theme: "night", variables: { colorPrimary: "#f97316" } },
            }}
          >
            <PaymentForm
              onSuccess={handlePaymentSuccess}
              onError={(msg) => { setErrorMsg(msg); setStep("error"); }}
              amount={totalAmount}
            />
          </Elements>
        )}

        {step === "error" && (
          <div className="text-center py-6 space-y-4">
            <AlertCircle className="w-16 h-16 text-destructive mx-auto" />
            <div>
              <h3 className="text-xl font-bold text-foreground">Payment Failed</h3>
              <p className="text-muted-foreground mt-2">{errorMsg}</p>
            </div>
            <div className="flex gap-3 justify-center">
              <Button variant="outline" onClick={() => onOpenChange(false)}>Cancel</Button>
              <Button variant="hero" onClick={() => setStep("details")}>Try Again</Button>
            </div>
          </div>
        )}
      </DialogContent>
    </Dialog>
  );
};

export default CartCheckoutModal;
