"use client";

import { useRouter } from "next/navigation";
import { useBookingStore } from "@/lib/booking-store";
import { usePaymentStore } from "@/lib/payment-store";
import { useMutation, useQuery } from "@tanstack/react-query";
import { apiClient } from "@/lib/api-client";
import { useState, useEffect } from "react";
import { PaymentMethod } from "@/types";
import { format } from "date-fns";
import { formatTime, getTimePeriod, toZonedDate } from '@/utils/format';
import { isChild, isFirstChild, formatFare } from '@/utils/fare-utils';
import {
  CreditCard,
  Smartphone,
  Wallet,
  Loader2,
  CheckCircle,
  ChevronLeft,
  KeyRound,
  Landmark,
} from "lucide-react";

const getIconForMethod = (methodId: string) => {
  if (methodId.includes('CARD')) return CreditCard;
  if (methodId.includes('WALLET')) return Wallet;
  if (methodId.includes('CAC')) return Landmark;
  return Smartphone;
};


export default function PaymentPage() {
  const router = useRouter();
  const { bookingId, pnr, selectedSchedule, outboundSchedule, inboundSchedule, passengers, searchCriteria, packageName, reviewedTotalMinor, reviewedPassengerFares } = useBookingStore();
  const { setPaymentIntent, updateStatus, setCurrency, setPaidAmount } = usePaymentStore();
  const [selectedMethod, setSelectedMethod] = useState<string | null>(null);
  const [isProcessing, setIsProcessing] = useState(false);
  const [paymentError, setPaymentError] = useState<string | null>(null);
  // CAC Bank OTP debit: on Pay, collect the payer's mobile in a modal, then the SMS'd OTP.
  const [payerMobile, setPayerMobile] = useState("");
  const [phoneModalOpen, setPhoneModalOpen] = useState(false);
  const [phoneError, setPhoneError] = useState<string | null>(null);
  const [otpModalOpen, setOtpModalOpen] = useState(false);
  const [otpCode, setOtpCode] = useState("");
  const [otpMessage, setOtpMessage] = useState<string | null>(null);
  const [otpError, setOtpError] = useState<string | null>(null);

  const isRoundTrip = searchCriteria?.tripType === 'ROUND_TRIP';

  // Use the same display currency as the review page — stored on the schedule at search time.
  const scheduleCurrency = isRoundTrip
    ? outboundSchedule?.displayCurrency
    : selectedSchedule?.displayCurrency;
  const nat = (searchCriteria?.nationality ?? '').toUpperCase();
  const displayCurrency = scheduleCurrency || (nat === 'DJIBOUTIAN' ? 'DJF' : nat === 'ETHIOPIAN' ? 'ETB' : 'USD');

  const { data: paymentMethods = [], isLoading: loadingMethods, error } = useQuery<PaymentMethod[]>({
    queryKey: ['paymentMethods'],
    queryFn: async () => {
      const response = await apiClient.get<PaymentMethod[]>(`/payments/methods`);
      return Array.isArray(response) ? response : [];
    },
  });

  const selectedPaymentMethod = paymentMethods.find(m => m.type === selectedMethod) || null;

  // Derive charge currency directly from the selected method — no separate state that can lag.
  const amountCurrency = (selectedPaymentMethod?.currency || 'ETB').toUpperCase();

  const { data: bookingAmountData, isFetching: fetchingAmount } = useQuery<{ amount: number; currency: string; booking_id: string }>({
    queryKey: ['bookingAmount', bookingId, amountCurrency],
    queryFn: async () => {
      const response: any = await apiClient.get(`/payments/booking-amount?bookingId=${bookingId}&currency=${amountCurrency}`);
      return response;
    },
    enabled: !!bookingId && !!selectedMethod,
    staleTime: 30_000,
  });

  // Data is only usable when it belongs to the currently-selected method's currency.
  const dataReady = !fetchingAmount && bookingAmountData != null && bookingAmountData.currency.toUpperCase() === amountCurrency.toUpperCase();

  // Per-leg subtotals for the journey header — sum each paying passenger's reviewed fare
  // split equally across both legs. This guarantees leg totals are consistent with the
  // per-passenger breakdown rows and the overall reviewed total.
  const outboundBaseFare = isRoundTrip
    ? (reviewedPassengerFares ?? []).reduce((sum, f) => sum + (f.isFree ? 0 : (f.outboundFareMinor ?? Math.round(f.fareMinor / 2))), 0)
    : 0;
  const inboundBaseFare = isRoundTrip
    ? (reviewedPassengerFares ?? []).reduce((sum, f) => sum + (f.isFree ? 0 : (f.inboundFareMinor ?? Math.round(f.fareMinor / 2))), 0)
    : 0;

  // reviewedTotalMinor is in display-currency minor units — matches what was shown on the review page.
  // When a method with a different currency is selected, bookingAmountData gives the converted charge amount.
  // When the method's currency matches displayCurrency (or no method selected), use reviewedTotal directly.
  const reviewedTotal = reviewedTotalMinor ?? (reviewedPassengerFares?.reduce((s, f) => s + f.fareMinor, 0) ?? null);

  // When a method is selected: show spinner until dataReady, then show converted amount.
  // When no method is selected: show the reviewed total in displayCurrency.
  const totalAmountDisplay = selectedMethod
    ? (dataReady ? bookingAmountData!.amount : null)
    : (reviewedTotal != null ? reviewedTotal / 100 : null);
  const totalAmount = selectedMethod && dataReady
    ? Math.round(bookingAmountData!.amount * 100)
    : (reviewedTotal ?? 0);
  const confirmedCurrency = selectedMethod
    ? (dataReady ? bookingAmountData!.currency : amountCurrency)
    : displayCurrency;
  const awaitingAmount = !!selectedMethod && !dataReady;

  useEffect(() => {
    if (selectedMethod && dataReady) {
      setCurrency(bookingAmountData!.currency as 'ETB' | 'DJF' | 'USD');
      setPaidAmount(Math.round(bookingAmountData!.amount * 100));
    } else if (!selectedMethod && reviewedTotal != null) {
      setCurrency(displayCurrency as 'ETB' | 'DJF' | 'USD');
      setPaidAmount(reviewedTotal);
    }
  }, [selectedMethod, dataReady, bookingAmountData, reviewedTotal, displayCurrency, setCurrency, setPaidAmount]);

  const paymentMutation = useMutation({
    mutationFn: async (data: any) => {
      return await apiClient.post("/payments/initiate", {
        bookingId: data.bookingId,
        method: data.method,
        paymentMethodId: data.paymentMethodId,
        payerAccount: data.payerAccount,
        platform: 'web',
      });
    },
    onSuccess: async (data: any) => {
      setPaymentError(null);

      // CAC Bank: no redirect — the bank SMS'd an OTP. Collect it in-app and confirm.
      if (data?.clientAction?.type === 'COLLECT_OTP') {
        setPaymentIntent(data.intentId);
        updateStatus("REQUIRES_ACTION");
        setOtpMessage(data.clientAction.message ?? "Enter the OTP sent to your phone");
        setOtpCode("");
        setOtpError(null);
        setOtpModalOpen(true);
        setIsProcessing(false);
        return;
      }

      if ((selectedMethod === 'TELEBIRR' || selectedMethod === 'WAAFI' || selectedMethod === 'DMONEY') && data?.clientAction?.type === 'REDIRECT') {
        setPaymentIntent(data.intentId);
        updateStatus("REQUIRES_ACTION");
        window.location.href = data.clientAction.url;
        return;
      }

      setPaymentIntent(data.paymentIntentId || data.intentId);
      updateStatus("PROCESSING");
      await new Promise((resolve) => setTimeout(resolve, 2000));
      updateStatus("SUCCEEDED");
      router.push("/booking/confirmation");
    },
    onError: (error: any) => {
      updateStatus("FAILED");
      setPaymentError(
        error?.response?.data?.message ||
        error?.message ||
        "Payment failed. Please try again.",
      );
      setIsProcessing(false);
    },
  });

  // CAC Bank OTP confirmation. A 200 means the payment settled; a 400 is a wrong/expired
  // OTP — keep the modal open so the payer can re-enter it (the intent stays open).
  const otpMutation = useMutation({
    mutationFn: async (otp: string) => {
      return await apiClient.post(`/payments/${bookingId}/confirm`, { otp });
    },
    onSuccess: () => {
      setOtpModalOpen(false);
      updateStatus("SUCCEEDED");
      router.push("/booking/confirmation");
    },
    onError: (error: any) => {
      setOtpError(
        error?.response?.data?.message ||
        error?.message ||
        "Invalid or expired OTP. Please try again.",
      );
    },
  });



  // Fire the actual initiate. `mobile` is only used for CAC (OTP debit).
  const startPayment = (mobile?: string) => {
    if (!selectedMethod || !bookingId || !selectedPaymentMethod) return;
    setIsProcessing(true);
    setPaymentError(null);
    paymentMutation.mutate({
      bookingId,
      method: selectedMethod,
      paymentMethodId: selectedPaymentMethod.id,
      currency: displayCurrency,
      amountMinor: totalAmount,
      payerAccount: selectedMethod === 'CAC_BANK' ? mobile?.trim() : undefined,
    });
  };

  const handlePayment = () => {
    if (!selectedMethod || !bookingId) {
      alert("Please select a payment method");
      return;
    }
    if (!selectedPaymentMethod) {
      alert("Invalid payment method selected");
      return;
    }
    setPaymentError(null);

    // CAC Bank needs the payer's mobile for the OTP — collect it in a modal before initiating.
    if (selectedMethod === 'CAC_BANK') {
      setPhoneError(null);
      setPhoneModalOpen(true);
      return;
    }

    startPayment();
  };

  const submitPhone = () => {
    if (!payerMobile.trim()) {
      setPhoneError("Please enter your mobile number");
      return;
    }
    setPhoneModalOpen(false);
    startPayment(payerMobile);
  };

  // Redirect if no booking data (but not during navigation)
  useEffect(() => {
    // Add a small delay to allow state to be set from previous page
    const timer = setTimeout(() => {
      if (!bookingId || !pnr) {
        router.push("/booking/search");
      }
    }, 500);

    return () => clearTimeout(timer);
  }, [bookingId, pnr, router]);

  if (!bookingId && !pnr) {
    return (
      <div className="booking-page flex items-center justify-center">
        <div className="text-center">
          <Loader2 className="w-12 h-12 text-primary animate-spin mx-auto mb-4" />
          <p className="text-gray-600 dark:text-gray-400">Loading payment details...</p>
        </div>
      </div>
    );
  }

  // Reusable journey leg timeline block
  const JourneyLeg = ({ schedule, color = 'primary', label, fare }: { schedule: any; color?: string; label: string; fare?: number }) => {
    const dotColor   = color === 'blue' ? 'border-blue-500' : 'border-primary';
    const lineColor  = color === 'blue' ? 'from-blue-500' : 'from-primary';
    const badgeBg    = color === 'blue' ? 'bg-blue-500/10 text-blue-600 dark:text-blue-400' : 'bg-primary/10 text-primary';
    return (
      <div>
        <div className="flex items-center gap-2 mb-3">
          <div className={`w-2 h-2 rounded-full ${color === 'blue' ? 'bg-blue-500' : 'bg-primary'}`} />
          <span className="text-sm font-semibold text-gray-700 dark:text-gray-300">{label}</span>
          <span className={`ml-auto text-xs px-2 py-0.5 rounded-full font-medium ${badgeBg}`}>
            {schedule?.selectedSeatClassName?.replace(/_/g, ' ') || 'Standard'}
          </span>
        </div>
        <div className="flex">
          <div className="flex flex-col items-center w-7 flex-shrink-0">
            <div className={`w-3 h-3 rounded-full border-4 ${dotColor} bg-white dark:bg-gray-900 z-10`} />
            <div className={`w-0.5 flex-1 bg-gradient-to-b ${lineColor} via-gray-300 dark:via-gray-700 to-gray-300 my-1.5`} />
            <div className="w-3 h-3 rounded-full border-4 border-gray-400 dark:border-gray-600 bg-white dark:bg-gray-900 z-10" />
          </div>
          <div className="flex-1 flex flex-col pl-2">
            <div className="pb-5">
              <div className="text-lg font-bold text-gray-900 dark:text-white">
                {schedule?.departureTime ? formatTime(schedule.departureTime) : '--:--'}
              </div>
              <div className="text-xs text-gray-500 dark:text-gray-400">
                {schedule?.departureTime
                  ? `${format(toZonedDate(new Date(schedule.departureTime)), 'EEE, MMM d')} · ${getTimePeriod(schedule.departureTime)}`
                  : ''}
              </div>
              <div className="text-sm font-semibold text-gray-900 dark:text-white mt-1">{schedule?.origin}</div>
            </div>
            <div className="pb-5 flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400">
              <span>{schedule?.duration}</span>
              <span>Train {schedule?.trainNumber}</span>
            </div>
            <div>
              <div className="text-lg font-bold text-gray-900 dark:text-white">
                {schedule?.arrivalTime ? formatTime(schedule.arrivalTime) : '--:--'}
              </div>
              <div className="text-xs text-gray-500 dark:text-gray-400">
                {schedule?.arrivalTime
                  ? `${format(toZonedDate(new Date(schedule.arrivalTime)), 'EEE, MMM d')} · ${getTimePeriod(schedule.arrivalTime)}`
                  : ''}
              </div>
              <div className="text-sm font-semibold text-gray-900 dark:text-white mt-1">{schedule?.destination}</div>
            </div>
          </div>
        </div>
        {fare !== undefined && (
          <div className="mt-3 pt-2 border-t border-gray-100 dark:border-gray-800 flex justify-between text-sm">
            <span className="text-gray-500 dark:text-gray-400">{label} fare</span>
            <span className="font-semibold text-gray-900 dark:text-gray-100">{confirmedCurrency} {(fare / 100).toFixed(2)}</span>
          </div>
        )}
      </div>
    );
  };

  // Order summary card — used in right sticky column (desktop) and inline (mobile)
  const OrderSummary = () => (
    <div className="card space-y-4">
      <h2 className="text-base font-bold text-gray-900 dark:text-gray-100 pb-2 border-b border-gray-100 dark:border-gray-800">
        Order summary
        <span className="ml-2 text-xs font-normal text-gray-500 dark:text-gray-400">
          Ref: <span className="font-bold text-gray-900 dark:text-gray-100">{pnr}</span>
        </span>
      </h2>

      {isRoundTrip ? (
        <div className="space-y-4">
          <JourneyLeg schedule={outboundSchedule} label="Outbound" fare={outboundBaseFare} />
          <div className="border-t-2 border-dashed border-gray-200 dark:border-gray-700 pt-4">
            <JourneyLeg schedule={inboundSchedule} color="blue" label="Return" fare={inboundBaseFare} />
          </div>
        </div>
      ) : (
        <JourneyLeg schedule={selectedSchedule} label="Your journey" />
      )}

      {/* Fare breakdown — sourced directly from review page to guarantee totals match */}
      <div className="pt-2 border-t-2 border-gray-200 dark:border-gray-700 space-y-2">
        <h3 className="text-sm font-bold text-gray-900 dark:text-gray-100">Fare breakdown</h3>
        {passengers.map((p, i) => {
          const reviewed = reviewedPassengerFares?.[i];
          const isChildPassenger = isChild(p);
          const isFreeChild = reviewed?.isFree ?? (isChildPassenger && isFirstChild(passengers, i));
          const passengerTotal = reviewed?.fareMinor ?? 0;

          return (
            <div key={i} className="border-b border-gray-100 dark:border-gray-800 pb-2 last:border-0">
              <div className="flex justify-between mb-0.5">
                <span className="text-sm font-medium text-gray-900 dark:text-gray-100 truncate max-w-[60%]">
                  {p.name || `Passenger ${i + 1}`}
                  {isChildPassenger && (
                    <span className={`text-xs font-semibold ml-1 ${
                      isFreeChild ? 'text-green-600' : 'text-blue-600'
                    }`}>
                      ({isFreeChild ? 'CHILD - FREE' : 'CHILD - FULL FARE'})
                    </span>
                  )}
                </span>
                <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">
                  {formatFare(passengerTotal, displayCurrency)}
                </span>
              </div>
              {isRoundTrip && !isFreeChild && (
                <div className="pl-3 space-y-0.5 text-xs text-gray-500 dark:text-gray-400">
                  <div className="flex justify-between">
                    <span>Outbound</span>
                    <span>{formatFare(reviewed?.outboundFareMinor ?? Math.round((reviewed?.fareMinor ?? 0) / 2), displayCurrency)}</span>
                  </div>
                  <div className="flex justify-between">
                    <span>Return</span>
                    <span>{formatFare(reviewed?.inboundFareMinor ?? Math.round((reviewed?.fareMinor ?? 0) / 2), displayCurrency)}</span>
                  </div>
                </div>
              )}
            </div>
          );
        })}
      </div>

      <div className="pt-2 border-t-2 border-gray-200 dark:border-gray-700">
        <div className="flex justify-between items-center">
          <span className="font-bold text-gray-900 dark:text-gray-100">Total</span>
          <span className="text-xl font-bold text-primary flex items-center gap-1.5">
            {awaitingAmount ? (
              <Loader2 className="w-4 h-4 animate-spin text-primary" />
            ) : (
              <>{confirmedCurrency} {(totalAmountDisplay ?? 0).toFixed(2)}</>
            )}
          </span>
        </div>
        {selectedPaymentMethod && !awaitingAmount && (
          <p className="text-xs text-gray-500 dark:text-gray-400 text-right mt-1">
            You will be charged {confirmedCurrency} {(totalAmountDisplay ?? 0).toFixed(2)} via {selectedPaymentMethod.displayName}
          </p>
        )}
      </div>

      {/* Pay + back buttons — desktop sidebar only */}
      <div className="hidden lg:flex flex-col gap-2 pt-1">
        {paymentError && (
          <p className="text-red-600 dark:text-red-400 text-xs">⚠️ {paymentError}</p>
        )}
        <button
          onClick={handlePayment}
          disabled={!selectedMethod || isProcessing || awaitingAmount}
          className="btn-primary w-full py-3 font-semibold disabled:opacity-50 disabled:cursor-not-allowed"
        >
          {isProcessing ? (
            <span className="flex items-center justify-center gap-2">
              <Loader2 className="w-4 h-4 animate-spin" /> Processing...
            </span>
          ) : awaitingAmount ? (
            <span className="flex items-center justify-center gap-2">
              <Loader2 className="w-4 h-4 animate-spin" /> Calculating amount...
            </span>
          ) : (
            `Pay ${confirmedCurrency} ${(totalAmountDisplay ?? 0).toFixed(2)}`
          )}
        </button>
        <button onClick={() => router.back()} disabled={isProcessing} className="btn-secondary w-full flex items-center justify-center gap-2">
          <ChevronLeft className="w-4 h-4" />
          Back
        </button>
        <p className="text-xs text-gray-500 dark:text-gray-400 text-center pt-1">
          🔒 Secure & encrypted payment
        </p>
      </div>
    </div>
  );

  return (
    <div className="booking-page pb-[calc(7rem+env(safe-area-inset-bottom))] lg:pb-10">
      <div className="container mx-auto px-4">
        <div className="max-w-6xl mx-auto">
          <h1 className="section-title">Complete payment</h1>

          {/* Reservation confirmation banner */}
          <div className="card bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 mb-4 flex items-start gap-3">
            <CheckCircle className="w-6 h-6 text-green-600 dark:text-green-400 flex-shrink-0 mt-0.5" />
            <div>
              <p className="text-sm font-semibold text-green-800 dark:text-green-300">
                {packageName ? `Your ${packageName} booking is successfully reserved` : 'Your booking is successfully reserved'}
              </p>
              <p className="text-sm text-green-700 dark:text-green-400 mt-0.5">
                Booking Reference: <span className="font-bold">{pnr}</span>
              </p>
              <p className="text-xs text-green-700/80 dark:text-green-400/80 mt-1">
                Please complete the payment below to confirm your booking. Your seats are held temporarily until payment is completed.
              </p>
            </div>
          </div>

          {/* Payment Processing Overlay */}
          {isProcessing && (
            <div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50">
              <div className="bg-white dark:bg-gray-800 rounded-xl p-8 max-w-sm w-full mx-4 text-center shadow-2xl">
                {paymentMutation.isSuccess ? (
                  <>
                    <CheckCircle className="w-14 h-14 text-green-500 mx-auto mb-4" />
                    <h3 className="text-lg font-bold mb-4 text-gray-900 dark:text-gray-100">Loading...</h3>
                    <Loader2 className="w-6 h-6 text-primary animate-spin mx-auto" />
                  </>
                ) : (
                  <>
                    <Loader2 className="w-14 h-14 text-primary animate-spin mx-auto mb-4" />
                    <h3 className="text-lg font-bold mb-1 text-gray-900 dark:text-gray-100">Processing payment</h3>
                    <p className="text-sm text-gray-500 dark:text-gray-400">Please wait...</p>
                  </>
                )}
              </div>
            </div>
          )}

          {/* CAC Bank — collect payer mobile before initiating */}
          {phoneModalOpen && (
            <div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 px-4">
              <div className="bg-white dark:bg-gray-800 rounded-xl p-6 max-w-sm w-full shadow-2xl">
                <div className="flex items-center gap-2 mb-1">
                  <Smartphone className="w-5 h-5 text-primary" />
                  <h3 className="text-lg font-bold text-gray-900 dark:text-gray-100">Your mobile number</h3>
                </div>
                <p className="text-sm text-gray-500 dark:text-gray-400 mb-4">
                  CAC Bank will send a one-time password to this number to authorize the payment.
                </p>
                <input
                  type="tel"
                  inputMode="numeric"
                  autoFocus
                  value={payerMobile}
                  onChange={(e) => { setPayerMobile(e.target.value); setPhoneError(null); }}
                  onKeyDown={(e) => { if (e.key === 'Enter') submitPhone(); }}
                  placeholder="77 XX XX XX"
                  className="w-full px-3 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:border-primary focus:ring-1 focus:ring-primary outline-none"
                />
                {phoneError && (
                  <p className="text-red-600 dark:text-red-400 text-xs mt-2">⚠️ {phoneError}</p>
                )}
                <div className="flex gap-2 mt-4">
                  <button
                    onClick={() => setPhoneModalOpen(false)}
                    className="btn-secondary flex-1 py-2.5"
                  >
                    Cancel
                  </button>
                  <button
                    onClick={submitPhone}
                    disabled={!payerMobile.trim()}
                    className="btn-primary flex-1 py-2.5 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    Continue
                  </button>
                </div>
              </div>
            </div>
          )}

          {/* CAC Bank OTP entry */}
          {otpModalOpen && (
            <div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 px-4">
              <div className="bg-white dark:bg-gray-800 rounded-xl p-6 max-w-sm w-full shadow-2xl">
                <div className="flex items-center gap-2 mb-1">
                  <KeyRound className="w-5 h-5 text-primary" />
                  <h3 className="text-lg font-bold text-gray-900 dark:text-gray-100">Enter OTP</h3>
                </div>
                <p className="text-sm text-gray-500 dark:text-gray-400 mb-4">
                  {otpMessage}
                </p>
                <input
                  type="text"
                  inputMode="numeric"
                  autoFocus
                  value={otpCode}
                  onChange={(e) => { setOtpCode(e.target.value.replace(/\D/g, '')); setOtpError(null); }}
                  onKeyDown={(e) => { if (e.key === 'Enter' && otpCode.trim() && !otpMutation.isPending) otpMutation.mutate(otpCode.trim()); }}
                  placeholder="Enter code"
                  maxLength={10}
                  className="w-full text-center tracking-[0.4em] text-lg font-semibold px-3 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:border-primary focus:ring-1 focus:ring-primary outline-none"
                />
                {otpError && (
                  <p className="text-red-600 dark:text-red-400 text-xs mt-2">⚠️ {otpError}</p>
                )}
                <div className="flex gap-2 mt-4">
                  <button
                    onClick={() => { setOtpModalOpen(false); updateStatus("REQUIRES_ACTION"); }}
                    disabled={otpMutation.isPending}
                    className="btn-secondary flex-1 py-2.5"
                  >
                    Cancel
                  </button>
                  <button
                    onClick={() => otpCode.trim() && otpMutation.mutate(otpCode.trim())}
                    disabled={otpMutation.isPending || !otpCode.trim()}
                    className="btn-primary flex-1 py-2.5 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    {otpMutation.isPending ? (
                      <span className="flex items-center justify-center gap-2">
                        <Loader2 className="w-4 h-4 animate-spin" /> Verifying...
                      </span>
                    ) : (
                      "Confirm payment"
                    )}
                  </button>
                </div>
              </div>
            </div>
          )}

          {/* Two-column grid */}
          <div className="lg:grid lg:grid-cols-3 lg:gap-6 lg:items-start">

            {/* Left column — payment methods (2/3 width) */}
            <div className="lg:col-span-2 space-y-4">
              <div className="card">
                <h2 className="text-base font-bold text-gray-900 dark:text-gray-100 mb-4">Select payment method</h2>
                {loadingMethods ? (
                  <div className="flex items-center justify-center py-10 gap-2">
                    <Loader2 className="w-6 h-6 text-primary animate-spin" />
                    <span className="text-sm text-gray-500 dark:text-gray-400">Loading payment methods...</span>
                  </div>
                ) : error ? (
                  <div className="bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg p-4">
                    <p className="text-red-800 dark:text-red-200 text-sm">Failed to load payment methods. Please refresh.</p>
                  </div>
                ) : paymentMethods.length === 0 ? (
                  <div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4">
                    <p className="text-yellow-800 dark:text-yellow-200 text-sm">No payment methods available at the moment.</p>
                  </div>
                ) : (
                  <div className="space-y-3">
                    {paymentMethods.filter(m => m.enabled).map((method) => {
                      const Icon = getIconForMethod(method.type);
                      const isSelected = selectedMethod === method.type;
                      return (
                        <button
                          key={method.id}
                          data-testid={`pay-method-${method.type}`}
                          onClick={() => setSelectedMethod(method.type)}
                          disabled={isProcessing || !method.enabled}
                          className={`w-full p-4 rounded-xl border-2 transition-all text-left ${
                            isSelected
                              ? 'border-primary bg-primary/8 dark:bg-primary/15 shadow-md'
                              : 'border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:border-primary/50'
                          } ${isProcessing || !method.enabled ? 'opacity-50 cursor-not-allowed' : ''}`}
                        >
                          <div className="flex items-center gap-3">
                            <div className={`w-11 h-11 rounded-lg flex items-center justify-center flex-shrink-0 ${isSelected ? 'bg-primary' : 'bg-gray-100 dark:bg-gray-700'}`}>
                              <Icon className={`w-5 h-5 ${isSelected ? 'text-white' : 'text-primary'}`} />
                            </div>
                            <div className="flex-1 min-w-0">
                              <p className="font-semibold text-gray-900 dark:text-gray-100">{method.displayName}</p>
                              <p className="text-xs text-gray-500 dark:text-gray-400">{method.region} · {method.currency}</p>
                            </div>
                            {isSelected && (
                              <CheckCircle className="w-5 h-5 text-primary flex-shrink-0" />
                            )}
                          </div>
                        </button>
                      );
                    })}
                  </div>
                )}
              </div>

              {/* Order summary inline — mobile only */}
              <div className="lg:hidden">
                <OrderSummary />
              </div>
            </div>

            {/* Right column — sticky order summary (desktop only) */}
            <div className="hidden lg:block">
              <div className="sticky top-6">
                <OrderSummary />
              </div>
            </div>

          </div>{/* end grid */}
        </div>
      </div>

      {/* Mobile sticky bottom bar */}
      <div className="lg:hidden fixed bottom-0 inset-x-0 bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 px-4 pt-3 pb-[calc(0.75rem+env(safe-area-inset-bottom))] z-40 shadow-lg">
        <div className="flex items-center justify-between mb-2.5">
          <span className="text-sm text-gray-600 dark:text-gray-400">Total</span>
          <span className="text-lg font-bold text-primary flex items-center gap-1.5">
            {awaitingAmount ? (
              <Loader2 className="w-3.5 h-3.5 animate-spin" />
            ) : (
              <>{confirmedCurrency} {(totalAmountDisplay ?? 0).toFixed(2)}</>
            )}
          </span>
        </div>
        {paymentError && (
          <p className="text-red-600 dark:text-red-400 text-xs mb-2">⚠️ {paymentError}</p>
        )}
        <div className="flex gap-3">
          <button onClick={() => router.back()} disabled={isProcessing} className="btn-secondary flex-1 py-2.5 flex items-center justify-center gap-2">
            <ChevronLeft className="w-4 h-4" />
            Back
          </button>
          <button
            onClick={handlePayment}
            disabled={!selectedMethod || isProcessing || awaitingAmount}
            className="btn-primary flex-1 py-2.5 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            {isProcessing ? (
              <span className="flex items-center justify-center gap-1.5">
                <Loader2 className="w-4 h-4 animate-spin" /> Processing...
              </span>
            ) : awaitingAmount ? (
              <span className="flex items-center justify-center gap-1.5">
                <Loader2 className="w-4 h-4 animate-spin" /> Calculating...
              </span>
            ) : (
              `Pay ${confirmedCurrency} ${(totalAmountDisplay ?? 0).toFixed(2)}`
            )}
          </button>
        </div>
      </div>

    </div>
  );
}
