"use client";

import Image from "next/image";
import { withCDN } from "@/src/lib/utils";
import { useState, useEffect, useMemo, Suspense } from "react";
import { ChevronDown, ChevronUp, Loader2, CreditCard, CalendarDays, ChevronLeft, ChevronRight, Lock } from "lucide-react";
import { useClassDetails } from "@/src/lib/context/ClassDetailsContext";
import { verifyCouponAction } from "@/src/lib/actions/couponAction";
import { submitFormAction } from "@/src/lib/actions/submitFormAction";
import { getFormsAction } from "@/src/lib/actions/formsAction";
import { getCheckoutPageDataAction } from "@/src/lib/actions/checkoutPageAction";
import { getPrivacyPolicyDataAction } from "@/src/lib/actions/privacyPolicyAction";
import { getTermsOfUseDataAction } from "@/src/lib/actions/termsOfUseAction";
import PrivacyPolicyModal from "@/src/components/ui/PrivacyPolicyModal";
import { interpolate } from "@/src/lib/utils/interpolate";
import { useLocalizedNavigation } from "@/src/lib/hooks/useLocalizedNavigation";
import { useLanguage } from "@/src/lib/context/LanguageContext";
import { resolveClasswiseAccountIdFromHostname } from "@/src/lib/utils/resolveClasswiseAccountId";
import { TextInputWithValidation, SelectDropdown } from "./FormRenderer";
import PhoneInput from "./PhoneInput";
import { useSearchParams } from "next/navigation";
import { getRegisterDetailsAction } from "@/src/lib/actions/registerDetailsAction";
import { getJSONCookie, setJSONCookie } from "@/src/lib/utils/cookies";
import { initiatePaymentAction, setupPaymentAction } from "@/src/lib/actions/paymentAction";
import { getPaymentStatusAction } from "@/src/lib/actions/paymentStatusAction";
import { formatPaymentErrorMessage } from "@/src/lib/utils/paymentErrorMessage";
import { fetchPaymentPlansAction } from "@/src/lib/actions/paymentPlansAction";
import StripePaymentFields from "./StripePaymentFields";
import RegistrationSidebar from "./RegistrationSidebar";
import StripeWalletFields from "./StripeWalletFields";
import { Elements, useStripe, useElements } from "@stripe/react-stripe-js";
import {
  extractClientSecretFromPayment,
  extractStripeAccountFromPayment,
  loadStripeConnect,
  writeStripeAccountToSession,
} from "@/src/lib/stripe/loadStripeConnect";
import { roundMoney } from "@/src/lib/utils/money";
/** Sync payment + trigger confirmation emails after client-side Stripe success (webhooks may not run locally). */
async function syncPaymentAndNotify(
  registrationId: string,
  intentId: string | null | undefined
) {
  if (!registrationId) {
    return;
  }

  await getPaymentStatusAction(registrationId, {
    paymentIntent: intentId?.startsWith("pi_") ? intentId : null,
    setupIntent: intentId?.startsWith("seti_") ? intentId : null,
  });
}

// Cookie that remembers a returning user's parent/child details (identity fields
// only — never payment/card data) so the registration form can prefill them.
const REGISTRANT_COOKIE = "ye_registrant";

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const nameRegex = /^[a-zA-Z\s\-']*$/;


export default function RegisterProgramForm({
  zohoFranchiseId,
  stripeAccountId: initialStripeAccountId = null,
}: {
  zohoFranchiseId?: string;
  stripeAccountId?: string | null;
}) {
  const connectedAccountId = initialStripeAccountId;

  const stripePromise = useMemo(() => {
    if (!connectedAccountId) {
      return null;
    }
    return loadStripeConnect(
      process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY || "",
      connectedAccountId
    );
  }, [connectedAccountId]);

  // A franchise with no gateway connected can still take registrations — they
  // collect the money on site, so there was never anything to charge here.
  // Blocking the whole page on a missing Stripe account turned that into a dead
  // end; instead fall through to the same registration-only flow that payer_id
  // "2" uses. `stripe={null}` keeps the Elements context present so the Stripe
  // hooks inside stay legal (they simply resolve to null).
  const paymentConfigured = Boolean(connectedAccountId && stripePromise);

  return (
    <Elements stripe={stripePromise} key={connectedAccountId || "no-payment"}>
      <Suspense fallback={<RegisterProgramFormLoading />}>
        <RegisterProgramFormContent
          zohoFranchiseId={zohoFranchiseId}
          connectedAccountId={connectedAccountId}
          paymentConfigured={paymentConfigured}
        />
      </Suspense>
    </Elements>
  );
}

function RegisterProgramFormLoading() {
  return (
    <section className="relative bg-transperent mt-10 py-10 px-5 xl:px-0 max-w-[1300px] mx-auto w-full">
      <div className="flex items-center justify-center py-24">
        <Loader2 className="w-8 h-8 animate-spin text-[#0097DC]" />
      </div>
    </section>
  );
}

function RegisterProgramFormContent({
  zohoFranchiseId,
  connectedAccountId,
  paymentConfigured,
}: {
  zohoFranchiseId?: string;
  connectedAccountId: string | null;
  paymentConfigured: boolean;
}) {
  const stripe = useStripe();
  const elements = useElements();
  const { classDetails } = useClassDetails();

  /**
   * No card is taken here — the visitor registers and settles up with the
   * franchise directly. Two separate reasons land in the same flow:
   *
   *  - payer_id "2": somebody other than the parent is paying for this class.
   *  - no gateway connected: this franchise collects on site.
   *
   * Deliberately NOT used for the sidebar's price, which stays keyed on
   * payer_id — an unconfigured franchise still charges the full amount, just
   * not through this page.
   */
  const registerOnly =
    String(classDetails?.payer_id) === "2" || !paymentConfigured;
  const { push } = useLocalizedNavigation();
  const { currentLanguage } = useLanguage();
  const searchParams = useSearchParams();
  const submissionId = searchParams.get("submission_id");

  const [form, setForm] = useState<any>(null);
  const [pageContent, setPageContent] = useState<any>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [agreed, setAgreed] = useState(false);
  const [coupon, setCoupon] = useState("");
  const [isVerifyingCoupon, setIsVerifyingCoupon] = useState(false);
  const [couponData, setCouponData] = useState<any>(null);
  const [couponError, setCouponError] = useState("");
  // Hide the coupon field until the user opts in ("Do you have a coupon?").
  const [showCoupon, setShowCoupon] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitted, setSubmitted] = useState(false);
  const [lastSubmissionId, setLastSubmissionId] = useState<string | null>(null);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [isReadOnly, setIsReadOnly] = useState(false);
  const [cardName, setCardName] = useState("");
  const [saveCard, setSaveCard] = useState(false);
  const [paymentError, setPaymentError] = useState<string | null>(null);
  const [isProcessingPayment, setIsProcessingPayment] = useState(false);
  const [isCardComplete, setIsCardComplete] = useState(false);

  // Dynamic wallet availability state
  const [walletAvailability, setWalletAvailability] = useState({ applePay: false, googlePay: false, link: false });

  // Privacy Policy modal state
  const [isPrivacyOpen, setIsPrivacyOpen] = useState(false);
  const [isPrivacyLoading, setIsPrivacyLoading] = useState(false);
  const [privacyContent, setPrivacyContent] = useState<{ heading?: string; effectiveDate?: string; content?: string } | null>(null);
  const [privacyFetched, setPrivacyFetched] = useState(false);
  const [privacyVersion, setPrivacyVersion] = useState<number | null>(null);
  const [privacyLang, setPrivacyLang] = useState<string | null>(null);

  const openPrivacyPolicy = async () => {
    setIsPrivacyOpen(true);
    if (privacyFetched) return;
    setIsPrivacyLoading(true);
    try {
      const response = await getPrivacyPolicyDataAction(
        classDetails?.franchise_id?.toString(),
        currentLanguage,
      );
      if (response?.success && response.data) {
        const section =
          response.data.translated?.privacyPolicy ||
          response.data.default?.privacyPolicy ||
          null;
        setPrivacyContent(section);
        setPrivacyVersion(response.data.version ?? null);
        setPrivacyLang(response.data.language_code ?? null);
      }
      setPrivacyFetched(true);
    } catch (error) {
      console.error("Error fetching privacy policy:", error);
    } finally {
      setIsPrivacyLoading(false);
    }
  };

  // Terms of Use modal state
  const [isTermsOpen, setIsTermsOpen] = useState(false);
  const [isTermsLoading, setIsTermsLoading] = useState(false);
  const [termsContent, setTermsContent] = useState<{ heading?: string; effectiveDate?: string; content?: string } | null>(null);
  const [termsFetched, setTermsFetched] = useState(false);
  const [termsVersion, setTermsVersion] = useState<number | null>(null);
  const [termsLang, setTermsLang] = useState<string | null>(null);

  const openTermsOfUse = async () => {
    setIsTermsOpen(true);
    if (termsFetched) return;
    setIsTermsLoading(true);
    try {
      const response = await getTermsOfUseDataAction(
        classDetails?.franchise_id?.toString(),
        currentLanguage,
      );
      if (response?.success && response.data) {
        const section =
          (response.data.translated as any)?.termsOfUse ||
          (response.data.translated as any)?.privacyPolicy ||
          (response.data.default as any)?.termsOfUse ||
          (response.data.default as any)?.privacyPolicy ||
          null;
        setTermsContent(section);
        setTermsVersion(response.data.version ?? null);
        setTermsLang(response.data.language_code ?? null);
      }
      setTermsFetched(true);
    } catch (error) {
      console.error("Error fetching terms of use:", error);
    } finally {
      setIsTermsLoading(false);
    }
  };

  // Payment plans states
  const [showPaymentPlans, setShowPaymentPlans] = useState(false);
  const [paymentPlans, setPaymentPlans] = useState<any[]>([]);
  const [isLoadingPlans, setIsLoadingPlans] = useState(false);
  const [plansError, setPlansError] = useState("");
  const [plansPage, setPlansPage] = useState(1);
  const PLANS_PER_PAGE = 5;

  // Form states
  const [parentInfo, setParentInfo] = useState({ firstName: "", lastName: "", email: "", phone: "" });
  const [childInfo, setChildInfo] = useState({ firstName: "", lastName: "", age: "", school: "" });
  const [paymentMethod, setPaymentMethod] = useState("card");

  useEffect(() => {
    if (classDetails) {
      if (registerOnly) {
        setPaymentMethod("later");
      } else if (paymentMethod === "later") {
        setPaymentMethod("card");
      }
    }
  }, [classDetails?.payer_id, registerOnly]);

  // Check Wallet Availability globally when Stripe loads
  useEffect(() => {
    if (stripe) {
      const pr = stripe.paymentRequest({
        country: "US",
        currency: "usd",
        total: { label: "Availability Check", amount: 100 },
      });
      pr.canMakePayment().then((result) => {
        if (result) {
          setWalletAvailability({
            applePay: !!result.applePay,
            googlePay: !!result.googlePay,
            link: !!result.link,
          });
        }
      });
    }
  }, [stripe]);

  useEffect(() => {
    async function loadSubmissionDetails() {
      if (!submissionId) {
        setIsLoading(false);
        return;
      }
      setIsLoading(true);
      try {
        const response = await getRegisterDetailsAction(submissionId);
        if (response?.status && response.data?.[0]) {
          const data = response.data[0];
          const submissionData = data.submission_data;
          const formDataArray = Array.isArray(submissionData) ? submissionData : Object.values(submissionData);

          // Match each step by the fields it carries, not by a specific step label —
          // different forms (footer/global vs class-detail) use different step names.
          const pDetails = formDataArray.find((d: any) =>
            d.step_1 === "parent_details" ||
            d.step_1 === "provide_parent_info" ||
            d.step_1 === "parent_information" ||
            d.full_name ||
            ((d.email || d.email_address) && (d.phone || d.phone_number))
          );
          const cDetails = formDataArray.find((d: any) =>
            d.step_2 === "child_details" ||
            d.step_2 === "provide_your_child_info" ||
            d.childs_name || d.age || d.school || d.childs_age
          );
          const payDetails = formDataArray.find((d: any) =>
            d.step_3 === "payment_details" || d.payment_method
          );

          if (pDetails) {
            // Footer/global form saves "full_name" + "email_address"; the
            // class-detail form uses "name" + "email". Accept both.
            const [firstName, ...lastNames] = (pDetails.full_name || pDetails.name || "").split(" ");
            setParentInfo({
              firstName: firstName || "",
              lastName: lastNames.join(" ") || "",
              email: pDetails.email || pDetails.email_address || "",
              // Kept as stored (e.g. "+91 7857004975"); formatPhoneNumber would
              // reshape the country code into a US-style "(917)" grouping.
              phone: pDetails.phone || pDetails.phone_number || "",
            });
          }

          if (cDetails) {
            // Footer form uses `name` for the child; class-detail form uses `childs_name`.
            const rawChildName = cDetails.childs_name || cDetails.name || "";
            const [cFirstName, ...cLastNames] = rawChildName.split(" ");
            setChildInfo({
              firstName: cFirstName || "",
              lastName: cLastNames.join(" ") || "",
              age: cDetails.age || cDetails.childs_age || "",
              school: cDetails.school || cDetails.grade || "",
            });
          }

          if (payDetails) {
            setPaymentMethod(payDetails.payment_method || "card");
            if (payDetails.coupon_code) {
              setCoupon(payDetails.coupon_code);
              // Open the section too — otherwise a restored code sat in state
              // behind a collapsed toggle, invisible and unremovable.
              setShowCoupon(true);
              setShowCoupon(true);
            }
          }

          setIsReadOnly(true);
          setAgreed(true);
        }
      } catch (error) {
        console.error("Failed to load submission details:", error);
      } finally {
        setIsLoading(false);
      }
    }
    loadSubmissionDetails();
  }, [submissionId]);

  // Prefill parent/child details from the cookie saved on a previous submission.
  // Only for a fresh registration — when editing a specific submission the server
  // data (loadSubmissionDetails) is the source of truth.
  useEffect(() => {
    if (submissionId) return;
    const saved = getJSONCookie<{
      parent?: Partial<typeof parentInfo>;
      child?: Partial<typeof childInfo>;
    }>(REGISTRANT_COOKIE);
    if (!saved) return;
    if (saved.parent) setParentInfo((prev) => ({ ...prev, ...saved.parent }));
    if (saved.child) setChildInfo((prev) => ({ ...prev, ...saved.child }));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [submissionId]);

  // Save the entered parent/child identity fields (NOT payment info) to a cookie
  // so a returning user's form is prefilled next time. Called on submit.
  const rememberRegistrant = () => {
    setJSONCookie(REGISTRANT_COOKIE, { parent: parentInfo, child: childInfo }, 30);
  };

  useEffect(() => {
    if (registerOnly) {
      setPaymentMethod("later");
    }
  }, [classDetails, registerOnly]);

  useEffect(() => {
    async function fetchPlans() {
      const groupId = classDetails?.id;
      const accountId = resolveClasswiseAccountIdFromHostname(
        zohoFranchiseId,
        classDetails?.franchise
      );
      const fId = searchParams.get("franchiseeId");

      if (!groupId || !accountId) return;

      setIsLoadingPlans(true);
      try {
        const response = await fetchPaymentPlansAction(
          String(groupId),
          accountId,
          fId,
          classDetails?.franchise
        );
        if (response.success && response.data.length > 0) {
          setPaymentPlans(response.data);
        }
      } catch (err) {
        console.error("Failed to fetch plans:", err);
      } finally {
        setIsLoadingPlans(false);
      }
    }
    fetchPlans();
  }, [classDetails, zohoFranchiseId, searchParams]);


  useEffect(() => {
    async function fetchForm() {
      try {
        const response = await getFormsAction(classDetails?.franchise_id?.toString());
        if (response.success) {
          setForm(response.data);
        }
      } catch (error) {
        console.error("Error fetching form:", error);
      }
    }
    if (classDetails) fetchForm();
  }, [classDetails]);

  useEffect(() => {
    async function fetchCheckoutPage() {
      try {
        const response = await getCheckoutPageDataAction(classDetails?.franchise_id?.toString(), currentLanguage);
        if (response?.success && response.data) {
          const contentObj = response.data.translated?.checkoutPage || response.data.default?.checkoutPage;
          if (contentObj) setPageContent(contentObj);
        }
      } catch (error) {
        console.error("Error fetching checkout page data:", error);
      }
    }
    fetchCheckoutPage();
  }, [classDetails?.franchise_id, currentLanguage]);

  // Prefetch both policy versions silently so version + language_code are always
  // recorded in policy_consents even if the user never opens the popups.
  useEffect(() => {
    if (!classDetails) return;
    const fid = classDetails.franchise_id?.toString();

    if (!privacyFetched) {
      getPrivacyPolicyDataAction(fid, currentLanguage).then((response) => {
        if (response?.success && response.data) {
          const section =
            response.data.translated?.privacyPolicy ||
            response.data.default?.privacyPolicy ||
            null;
          setPrivacyContent(section);
          setPrivacyVersion(response.data.version ?? null);
          setPrivacyLang(response.data.language_code ?? null);
          setPrivacyFetched(true);
        }
      }).catch(() => { });
    }

    if (!termsFetched) {
      getTermsOfUseDataAction(fid, currentLanguage).then((response) => {
        if (response?.success && response.data) {
          const section =
            (response.data.translated as any)?.termsOfUse ||
            (response.data.translated as any)?.privacyPolicy ||
            (response.data.default as any)?.termsOfUse ||
            (response.data.default as any)?.privacyPolicy ||
            null;
          setTermsContent(section);
          setTermsVersion(response.data.version ?? null);
          setTermsLang(response.data.language_code ?? null);
          setTermsFetched(true);
        }
      }).catch(() => { });
    }
  }, [classDetails, currentLanguage]);

  const perUnitPrice = classDetails
    ? roundMoney(
      parseFloat(String(classDetails.value ?? (classDetails as { price?: string }).price ?? "0"))
    )
    : 0;
  const lessonCount = classDetails ? parseInt(String(classDetails.number_of_lessons), 10) || 1 : 1;

  const getDiscountAmount = () => {
    if (!couponData) return 0;
    if (couponData.discount_type === "percentage") {
      return roundMoney((perUnitPrice * couponData.discount) / 100);
    }
    return roundMoney(Number(couponData.discount) || 0);
  };

  const hasPaymentPlans = paymentPlans.length > 0;
  const amountDueNow = roundMoney(
    hasPaymentPlans
      ? parseFloat(paymentPlans[0]?.amount) || 0
      : Math.max(0, perUnitPrice * lessonCount - getDiscountAmount())
  );
  /** Total value of the class = unit price × number of lessons (not sum of installments). */
  const totalClassValue = roundMoney(
    Math.max(0, perUnitPrice * lessonCount - getDiscountAmount())
  );
  const paymentFrequency = String(classDetails?.payment_charges_frequency || "per_lesson").toLowerCase();
  const frequencyLabelMap: Record<string, string> = {
    weekly: "Weekly",
    monthly: "Monthly",
    daily: "Daily",
    per_lesson: "Per lesson",
  };
  const paymentFrequencyLabel = frequencyLabelMap[paymentFrequency] || paymentFrequency.replace(/_/g, " ");
  const feeBasis = String(classDetails?.fee_basis || "per_lesson").toLowerCase();
  const priceUnitSuffix = feeBasis.includes("month") ? "per month" : feeBasis.includes("week") ? "per week" : "per lesson";

  /** @deprecated use amountDueNow — kept for sidebar prop name compatibility */
  const finalPrice = amountDueNow;
  const displayPaymentAmount = amountDueNow;
  const formatAmount = (value: number) =>
    Number.isInteger(value) ? value.toString() : value.toFixed(2);

  const buildPaymentStepFields = () => ({
    step_3: "payment_details",
    payment_method: paymentMethod,
    coupon_code: couponData?.coupon_code || "",
    discount_amount: getDiscountAmount(),
    final_price: amountDueNow,
    amount_due_now: amountDueNow,
    total_class_value: totalClassValue,
    total_program_price: totalClassValue,
    per_unit_price: perUnitPrice,
    number_of_lessons: lessonCount,
    payment_charges_frequency: paymentFrequency,
    payment_frequency_label: paymentFrequencyLabel,
    price_per_lesson_display: `$${formatAmount(perUnitPrice)} ${priceUnitSuffix}`,
    installment_number: hasPaymentPlans ? 1 : null,
    installment_total: hasPaymentPlans ? paymentPlans.length : null,
  });

  const validateField = (name: string, value: string, type: string = "text", isRequired: boolean = true) => {
    let error = "";
    if (isRequired && (!value || value.trim() === "")) {
      error = "This field is required";
    } else if (value && value.trim() !== "") {
      if (type === "email" && !emailRegex.test(value)) {
        error = "Please enter a valid email address";
      } else if (type === "phone") {
        const digits = value.replace(/\D/g, "");
        if (digits.length < 10 || digits.length > 14) {
          error = "Please enter a valid phone number (10 to 14 digits)";
        }
      } else if (type === "name" && !nameRegex.test(value)) {
        error = "Should only contain letters, spaces, and hyphens";
      }
    }
    setErrors(prev => ({ ...prev, [name]: error }));
    return error === "";
  };

  const handleApplyCoupon = async () => {
    if (!coupon.trim() || !classDetails?.id) return;
    setIsVerifyingCoupon(true);
    setCouponError("");
    try {
      const response = await verifyCouponAction(coupon.trim(), classDetails.id);
      if (response.success) {
        setCouponData(response.data);
      } else {
        setCouponError(response.message || "Invalid coupon code");
        setCouponData(null);
      }
    } catch (error) {
      setCouponError("Failed to verify coupon");
    } finally {
      setIsVerifyingCoupon(false);
    }
  };

  // --- STANDARD CARD SUBMISSION ---
  const handleSubmit = async () => {
    if (isReadOnly) {
      handlePayNow();
      return;
    }

    setErrors({});
    const p1 = validateField("parent_first_name", parentInfo.firstName, "name");
    const p2 = validateField("parent_last_name", parentInfo.lastName, "name", false);
    const p3 = validateField("parent_email", parentInfo.email, "email");
    const p4 = validateField("parent_phone", parentInfo.phone, "phone");
    const c1 = validateField("child_first_name", childInfo.firstName, "name");
    const c2 = validateField("child_last_name", childInfo.lastName, "name", false);
    const c3 = validateField("child_age", childInfo.age);
    const c4 = validateField("child_school", childInfo.school);

    if (!p1 || !p2 || !p3 || !p4 || !c1 || !c2 || !c3 || !c4) {
      setErrors(prev => ({ ...prev, form: "Please fix the errors in the form before submitting." }));
      return;
    }
    if (!agreed) {
      setErrors(prev => ({ ...prev, policy: "Please agree to the Privacy Policy and Terms of Use." }));
      return;
    }
    if (paymentMethod === "card") {
      if (!cardName.trim()) {
        setErrors(prev => ({ ...prev, form: "Please enter the name on the card." }));
        return;
      }
      if (!isCardComplete) {
        setErrors(prev => ({ ...prev, form: "Please enter valid card details." }));
        return;
      }
    }

    // Wallet methods (Google Pay, Apple Pay, Link) have their own payment button
    // rendered by StripeWalletFields. Clicking the generic "Register and Pay" button
    // while a wallet method is selected must NOT submit the form — that would create a
    // registration record without any payment being processed.
    if (paymentMethod === "google" || paymentMethod === "apple" || paymentMethod === "link") {
      setErrors(prev => ({
        ...prev,
        form: "Please use the Google Pay or Apple Pay button above to complete your registration and payment.",
      }));
      return;
    }

    if (!classDetails) return;

    setIsSubmitting(true);
    try {
      const formData = [
        { step_1: "parent_details", name: `${parentInfo.firstName} ${parentInfo.lastName}`, email: parentInfo.email, phone: parentInfo.phone },
        { step_2: "child_details", "childs_name": `${childInfo.firstName} ${childInfo.lastName}`, age: childInfo.age, school: childInfo.school },
        buildPaymentStepFields(),
        {
          policy_consents: [
            { type: "privacy_policy", language_code: privacyLang, version: privacyVersion },
            { type: "terms_of_use", language_code: termsLang, version: termsVersion },
          ],
        },
      ];

      const classData = {
        group_id: classDetails.id,
        franchise_id: classDetails.franchise_id,
        group_name: classDetails.group_name,
        program_name: classDetails.program?.title || classDetails.program?.name || "",
        instructor_name: classDetails.instructors?.[0]?.name || "",
        start_date: classDetails.start_date,
        start_time: classDetails.start_time,
        end_time: classDetails.end_time,
        day: classDetails.day || [],
        location: classDetails.p_o_s?.name || classDetails.p_o_s?.location || "",
        min_age: classDetails.min_age,
        max_age: classDetails.max_age,
        price: perUnitPrice,
        number_of_lessons: lessonCount,
        total_class_value: totalClassValue,
        total_program_price: totalClassValue,
        amount_due_now: amountDueNow,
        payment_charges_frequency: paymentFrequency,
        price_name: classDetails.fee_basis,
        payer_id: classDetails.payer_id,
        invoice_tax_value: classDetails.invoice_tax || classDetails.franchise?.invoice_tax_value,
        invoice_tax_label: classDetails.invoice_tax_label || classDetails.franchise?.invoice_tax_label,
        company_name: classDetails.franchise?.company_name,
        company_address: classDetails.franchise?.company_address,
      };



      const payload = {
        form_id: form?.id || "registration_form",
        form_data: formData,
        slug: "home",
        class_details: classData
      };




      const response = (await submitFormAction(payload)) as any;

      if (response.status && response.submission_id) {
        // Remember this registrant's details for next time (prefill).
        rememberRegistrant();
        setLastSubmissionId(response.submission_id);
        if (paymentMethod === "card") {
          await handlePayNow(response.submission_id);
        } else if (paymentMethod === "later") {
          // Pay-later: registration is intentionally created without upfront payment.
          push(`/thank-you/${response.submission_id}?paylater=true`);
        } else {
          // Defensive fallback — should not be reached after the guard above.
          setErrors(prev => ({
            ...prev,
            form: "Please use the wallet payment button above to complete your payment.",
          }));
        }
      } else {
        alert(response.message || "Failed to submit registration");
      }
    } catch (error) {
      console.error("Error submitting form:", error);
      alert("An error occurred. Please try again.");
    } finally {
      setIsSubmitting(false);
    }
  };

  // --- WALLET SUBMISSION (APPLE PAY / GOOGLE PAY) ---
  const handleWalletPaymentAuth = async (ev: any) => {
    setErrors({});
    setPaymentError(null);

    // 1. Validate Form First
    const p1 = validateField("parent_first_name", parentInfo.firstName, "name");
    const p2 = validateField("parent_last_name", parentInfo.lastName, "name", false);
    const p3 = validateField("parent_email", parentInfo.email, "email");
    const p4 = validateField("parent_phone", parentInfo.phone, "phone");
    const c1 = validateField("child_first_name", childInfo.firstName, "name");
    const c2 = validateField("child_last_name", childInfo.lastName, "name", false);
    const c3 = validateField("child_age", childInfo.age);
    const c4 = validateField("child_school", childInfo.school);

    if (!p1 || !p2 || !p3 || !p4 || !c1 || !c2 || !c3 || !c4) {
      setErrors(prev => ({ ...prev, form: "Please complete all required fields before using Wallet Pay." }));
      ev.complete("fail");
      return;
    }
    if (!agreed) {
      setErrors(prev => ({ ...prev, policy: "Please agree to the Privacy Policy and Terms of Use before paying." }));
      ev.complete("fail");
      return;
    }
    if (!classDetails) {
      ev.complete("fail");
      return;
    }

    setIsSubmitting(true);

    try {
      // 2. Submit Form Data
      const formData = [
        { step_1: "parent_details", name: `${parentInfo.firstName} ${parentInfo.lastName}`, email: parentInfo.email, phone: parentInfo.phone },
        { step_2: "child_details", "childs_name": `${childInfo.firstName} ${childInfo.lastName}`, age: childInfo.age, school: childInfo.school },
        buildPaymentStepFields(),
        {
          policy_consents: [
            { type: "privacy_policy", language_code: privacyLang, version: privacyVersion },
            { type: "terms_of_use", language_code: termsLang, version: termsVersion },
          ],
        },
      ];

      const classData = {
        group_id: classDetails.id,
        franchise_id: classDetails.franchise_id,
        group_name: classDetails.group_name,
        program_name: classDetails.program?.title || classDetails.program?.name || "",
        instructor_name: classDetails.instructors?.[0]?.name || "",
        start_date: classDetails.start_date,
        start_time: classDetails.start_time,
        end_time: classDetails.end_time,
        day: classDetails.day || [],
        location: classDetails.p_o_s?.name || classDetails.p_o_s?.location || "",
        min_age: classDetails.min_age,
        max_age: classDetails.max_age,
        price: perUnitPrice,
        number_of_lessons: lessonCount,
        total_class_value: totalClassValue,
        total_program_price: totalClassValue,
        amount_due_now: amountDueNow,
        payment_charges_frequency: paymentFrequency,
        price_name: classDetails.fee_basis,
        payer_id: classDetails.payer_id,
        invoice_tax_value: classDetails.invoice_tax || classDetails.franchise?.invoice_tax_value,
        invoice_tax_label: classDetails.invoice_tax_label || classDetails.franchise?.invoice_tax_label,
        company_name: classDetails.franchise?.company_name,
        company_address: classDetails.franchise?.company_address,
      };

      const payload = {
        form_id: form?.id || "registration_form",
        form_data: formData,
        slug: "home",
        class_details: classData
      };

      const response = (await submitFormAction(payload)) as any;
      const subId = response.submission_id || submissionId;

      if (!response.status || !subId) {
        setErrors(prev => ({ ...prev, form: response.message || "Failed to submit registration" }));
        ev.complete("fail");
        return;
      }
      setLastSubmissionId(subId);
      // Remember this registrant's details for next time (prefill).
      rememberRegistrant();

      // 3. Initiate Payment with Backend to get client_secret
      const paymentResponse = await initiatePaymentAction({
        user_id: 1,
        gateway: "stripe",
        amount: amountDueNow,
        currency: "usd",
        email: parentInfo.email,
        registration_id: subId,
        class_id: classDetails.id,
        class_name: classDetails.group_name,
        fee_basis: classDetails.fee_basis,
        save_card: false, // Don't typically save wallet cards via standard boolean
      } as any);

      const paymentData = Array.isArray(paymentResponse.data) ? paymentResponse.data[0] : paymentResponse.data;
      const clientSecret = extractClientSecretFromPayment(paymentData);
      const stripeAccountId = extractStripeAccountFromPayment(paymentData);
      const intentId =
        paymentData?.payment_intent_id ||
        paymentData?.response?.id ||
        (clientSecret ? clientSecret.split("_secret_")[0] : null);

      if (intentId && subId) {
        sessionStorage.setItem(`payment_intent_${subId}`, intentId);
        if (clientSecret) {
          sessionStorage.setItem(`payment_${subId}`, clientSecret);
        }
      }

      if (stripeAccountId) {
        writeStripeAccountToSession(subId, stripeAccountId);
      }

      if (!clientSecret || !stripeAccountId || !stripe) {
        ev.complete("fail");
        setPaymentError("Payment configuration error: Stripe is not ready.");
        return;
      }

      // Must use the same Stripe instance that created the Elements (useStripe hook)
      const { error, paymentIntent } = await stripe.confirmCardPayment(
        clientSecret,
        { payment_method: ev.paymentMethod.id },
        { handleActions: true }
      );

      if (error) {
        ev.complete("fail");
        setPaymentError(error.message || "Payment failed");
      } else if (
        paymentIntent?.status === "succeeded" ||
        paymentIntent?.status === "processing"
      ) {
        ev.complete("success");
        await syncPaymentAndNotify(subId, paymentIntent?.id ?? intentId);
        const statusParam =
          paymentIntent.status === "processing" ? "processing" : "succeeded";
        const thankYouParams = new URLSearchParams({ redirect_status: statusParam });
        if (paymentIntent?.id) {
          thankYouParams.set("payment_intent", paymentIntent.id);
        }
        push(`/thank-you/${subId}?${thankYouParams.toString()}`);
      } else if (paymentIntent?.status === "requires_action") {
        ev.complete("success");
        setPaymentError("Additional authentication is required. Please complete payment on the next screen.");
        push(`/pay/${subId}`);
      } else {
        ev.complete("fail");
        setPaymentError("Payment could not be completed.");
      }
    } catch (error) {
      console.error("Wallet auth error:", error);
      ev.complete("fail");
      setPaymentError("An error occurred during payment processing.");
    } finally {
      setIsSubmitting(false);
    }
  };

  const handlePayNow = async (passedSubmissionId?: string) => {
    const idToUse = passedSubmissionId || submissionId;
    if (!idToUse) return;

    setIsProcessingPayment(true);
    setPaymentError(null);
    try {
      let response;
      const email = parentInfo.email;
      const isDemo = String(classDetails?.value) === "0" || !classDetails?.value;

      if (isDemo) {
        response = await setupPaymentAction({
          user_id: 1,
          gateway: "stripe",
          email: email,
          registration_id: idToUse,
          save_card: saveCard,
        });
      } else {
        response = await initiatePaymentAction({
          user_id: 1,
          gateway: "stripe",
          amount: amountDueNow,
          currency: "usd",
          email: email,
          registration_id: idToUse,
          class_id: classDetails.id,
          class_name: classDetails.group_name,
          fee_basis: classDetails.fee_basis,
          save_card: saveCard,
        } as any);
      }

      if (response.status && response.data) {
        const paymentData = Array.isArray(response.data) ? response.data[0] : response.data;
        const clientSecret = extractClientSecretFromPayment(paymentData);
        const intentId =
          paymentData?.payment_intent_id ||
          paymentData?.response?.id ||
          (clientSecret ? clientSecret.split("_secret_")[0] : null);

        const stripeAccountId = extractStripeAccountFromPayment(paymentData);

        if (intentId && idToUse) {
          sessionStorage.setItem(`payment_intent_${idToUse}`, intentId);
          if (clientSecret) {
            sessionStorage.setItem(`payment_${idToUse}`, clientSecret);
          }
          writeStripeAccountToSession(idToUse, stripeAccountId);
        }

        if (!stripeAccountId) {
          setPaymentError("Payment configuration error: Stripe connected account missing.");
          setIsProcessingPayment(false);
          return;
        }

        if (!clientSecret) {
          setPaymentError("Payment could not be started. Please try again.");
          setIsProcessingPayment(false);
          return;
        }

        if (clientSecret && stripe && elements) {
          const isSetupIntent = clientSecret.startsWith("seti_");
          let stripeError;

          const cardElement = elements.getElement("cardNumber");
          if (!cardElement) {
            setPaymentError("Payment UI error: Card element not found.");
            setIsProcessingPayment(false);
            return;
          }

          if (isSetupIntent) {
            const { error } = await stripe.confirmCardSetup(clientSecret, {
              payment_method: {
                card: cardElement,
                billing_details: { name: cardName, email: parentInfo.email },
              },
            });
            stripeError = error;
          } else {
            const { error } = await stripe.confirmCardPayment(clientSecret, {
              payment_method: {
                card: cardElement,
                billing_details: { name: cardName, email: parentInfo.email },
              },
            });
            stripeError = error;
          }

          if (stripeError) {
            setPaymentError(stripeError.message || "Payment failed");
          } else {
            await syncPaymentAndNotify(idToUse, intentId);
            const thankYouParams = new URLSearchParams({ redirect_status: "succeeded" });
            if (intentId) {
              thankYouParams.set(
                intentId.startsWith("seti_") ? "setup_intent" : "payment_intent",
                intentId
              );
            }
            push(`/thank-you/${idToUse}?${thankYouParams.toString()}`);
          }
        } else {
          push(`/pay/${idToUse}`);
        }
      } else {
        setPaymentError(formatPaymentErrorMessage(response.message));
      }
    } catch (error) {
      setPaymentError(formatPaymentErrorMessage(
        error instanceof Error ? error.message : undefined
      ));
    } finally {
      setIsProcessingPayment(false);
    }
  };

  const isFormFilled =
    parentInfo.firstName.trim() !== "" &&
    parentInfo.email.trim() !== "" &&
    parentInfo.phone.trim() !== "" &&
    childInfo.firstName.trim() !== "" &&
    childInfo.age.trim() !== "" &&
    childInfo.school.trim() !== "" &&
    agreed &&
    (paymentMethod !== "card" || (cardName.trim() !== "" && isCardComplete));

  if (!classDetails) return null;

  return (
    <section className="relative bg-transperent mt-10 py-10 px-5 xl:px-0 max-w-[1300px] mx-auto w-full registration-form">
      {/* Minimal Elegant Back Link */}
      <div className="mb-8">
        <button
          onClick={() => push("/class-registration")}
          className="inline-flex items-center gap-2 text-[#0097DC] hover:text-[#0097DC] font-medium text-[15px] transition-colors cursor-pointer group"
        >
          <ChevronLeft className="w-5 h-5 transition-transform group-hover:-translate-x-1 text-[#0097DC]" />
          <span>Back to Classes</span>
        </button>
      </div>

      <div className="max-w-[1300px] mx-auto flex flex-col-reverse md:flex-row gap-[60px] md:gap-[30px] lg:gap-[70px] justify-between">
        <div className="flex-1 w-full min-w-0 min-[768px]:max-[1024px]:max-w-[400px] max-[767px]:max-w-full registration-left-section">
          <div className="text-center mb-10">
            <h2 className="text-[30px] md:text-[30px] lg:text-[40px] xl:text-[40px] 2xl:text-[40px] leading-tight font-bold text-[#58585A] uppercase tracking-wide">
              {pageContent?.registerMainHeading || "Register For A Program"}
            </h2>
            <p className="text-[14px] md:text-[14px] lg:text-[20px] xl:text-[22px] 2xl:text-[24px] text-[#58585A] mt-2">
              {pageContent?.registerSubHeading || "Fill in the form to join the classes"}
            </p>
          </div>

          {/* 1. Parent Info */}
          <div className="border-b border-[#ddd] pb-5 mb-4 lg:pb-8 lg:mb-8">
            <h3 className="text-[20px] text-[#58585A] mb-5 font-light">
              {pageContent?.parentDetailText || (<>1. Provide <span className="font-regular">parent</span> info</>)}
            </h3>
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 form-grid">
              <div className="flex flex-col gap-2">
                <TextInputWithValidation
                  placeholder={pageContent?.nameText || "First name"}
                  value={parentInfo.firstName}
                  onChange={(e) => setParentInfo({ ...parentInfo, firstName: e.target.value })}
                  onBlur={() => validateField("parent_first_name", parentInfo.firstName, "name")}
                  error={errors["parent_first_name"]}
                  disabled={isReadOnly}
                />
              </div>
              <div className="flex flex-col gap-2">
                <TextInputWithValidation
                  placeholder={pageContent?.lastNameText || "Last name"}
                  value={parentInfo.lastName}
                  onChange={(e) => setParentInfo({ ...parentInfo, lastName: e.target.value })}
                  onBlur={() => validateField("parent_last_name", parentInfo.lastName, "name", false)}
                  error={errors["parent_last_name"]}
                  disabled={isReadOnly}
                />
              </div>
              <div className="flex flex-col gap-2">
                <TextInputWithValidation
                  placeholder={pageContent?.emailText || "E-mail"}
                  type="email"
                  value={parentInfo.email}
                  onChange={(e) => setParentInfo({ ...parentInfo, email: e.target.value })}
                  onBlur={() => validateField("parent_email", parentInfo.email, "email")}
                  error={errors["parent_email"]}
                  disabled={isReadOnly}
                />
              </div>
              <div className="flex flex-col gap-2">
                {/* Same country-picker input the footer/contact forms already
                    use (FormRenderer routes CMS `number` fields to it), so the
                    phone field looks and behaves identically everywhere. It
                    stores "<dial> <national>" — the exact shape the prefill
                    below already supplies, unlike formatPhoneNumber which
                    reshaped a country code into a US-style "(917)" grouping. */}
                <PhoneInput
                  placeholder={pageContent?.phoneText || "Enter your phone number"}
                  value={parentInfo.phone}
                  onChange={(combined) => setParentInfo({ ...parentInfo, phone: combined })}
                  onBlur={() => validateField("parent_phone", parentInfo.phone, "phone")}
                  error={errors["parent_phone"]}
                  disabled={isReadOnly}
                />
              </div>
            </div>
          </div>

          {/* 2. Child Info */}
          <div className="border-b border-[#ddd] pb-5 mb-4 lg:pb-8 lg:mb-8">
            <h3 className="text-[20px] text-[#58585A] mb-5 font-light">
              {pageContent?.childDetailText || (<>2. Provide your <span className="font-regular">child</span> info</>)}
            </h3>
            <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 from-grid-2">
              <div className="flex flex-col gap-2">
                <TextInputWithValidation
                  placeholder={pageContent?.childFirstNameText || "First name"}
                  value={childInfo.firstName}
                  onChange={(e) => setChildInfo({ ...childInfo, firstName: e.target.value })}
                  onBlur={() => validateField("child_first_name", childInfo.firstName, "name")}
                  error={errors["child_first_name"]}
                  disabled={isReadOnly}
                />
              </div>
              <div className="flex flex-col gap-2">
                <TextInputWithValidation
                  placeholder={pageContent?.childLastNameText || "Last name"}
                  value={childInfo.lastName}
                  onChange={(e) => setChildInfo({ ...childInfo, lastName: e.target.value })}
                  onBlur={() => validateField("child_last_name", childInfo.lastName, "name", false)}
                  error={errors["child_last_name"]}
                  disabled={isReadOnly}
                />
              </div>
              <div className="flex flex-col gap-2">
                <SelectDropdown
                  placeholder={pageContent?.ageText || "Age"}
                  value={childInfo.age}
                  onChange={(val) => {
                    setChildInfo({ ...childInfo, age: val });
                    validateField("child_age", val);
                  }}
                  // Age ranges, matching the options the footer form offers.
                  options={["4-6", "7-10", "11-12", "13-18"]}
                  disabled={isReadOnly}
                />
                {errors["child_age"] && <p className="text-red-500 text-[13px] ml-4 mt-1">{errors["child_age"]}</p>}
              </div>
              <div className="flex flex-col gap-2">
                <SelectDropdown
                  placeholder={pageContent?.schoolTypeText || "School"}
                  value={childInfo.school}
                  onChange={(val) => {
                    setChildInfo({ ...childInfo, school: val });
                    validateField("child_school", val);
                  }}
                  options={["Public School", "Private School", "Home School", "Other"]}
                  disabled={isReadOnly}
                />
                {errors["child_school"] && <p className="text-red-500 text-[13px] ml-4 mt-1">{errors["child_school"]}</p>}
              </div>
            </div>
          </div>

          <div className="mt-1">
            {!registerOnly && (
              <>
                {/* 3. Program Summary */}
                <div className="border-b border-[#ddd] pb-5 mb-4 lg:pb-8 lg:mb-8 mt-5">
                  <h3 className="text-[18px] md:text-[20px] text-[#58585A] font-light">
                    3. The chosen program includes {lessonCount} lessons with {paymentFrequencyLabel.toLowerCase()} payments of ${formatAmount(perUnitPrice)}.
                  </h3>
                </div>

                {/* 4. Coupon */}
                <div className="border-b border-[#ddd] pb-5 mb-4 lg:pb-8 lg:mb-8">
                  <h3 className="text-[20px] text-[#58585A] font-light mb-2 lg:mb-5">
                    {pageContent?.couponSectionTitleText?.replace(/^3\./, '4.') || "4. Have a coupon?"}
                  </h3>

                  {/*
                Opt-in: only reveal the code field when the user has a coupon.

                Deliberately NOT gated on isReadOnly. That flag locks the
                parent/child/class details already captured in the submission,
                but the coupon belongs to the payment step, which has not
                happened yet on this screen. Hiding it left the "Discount Code"
                heading with nothing underneath and denied a discount at the
                exact moment the visitor is about to pay.
              */}
                  <label className="flex items-center gap-2 cursor-pointer mb-4 select-none w-fit">
                    <input
                      type="checkbox"
                      checked={showCoupon}
                      onChange={(e) => {
                        const checked = e.target.checked;
                        setShowCoupon(checked);
                        // Clearing on uncheck so a hidden coupon can't stay applied.
                        if (!checked) {
                          setCoupon("");
                          setCouponData(null);
                          setCouponError("");
                        }
                      }}
                      className="w-[20px] h-[20px] accent-[#0097dc] cursor-pointer"
                    />
                    <span className="text-[16px] text-[#58585A]">
                      {pageContent?.couponToggleText || "Do you have a coupon?"}
                    </span>
                  </label>

                  {showCoupon && (
                    <div className="max-w-[320px]">
                      <div className="flex flex-col gap-2">
                        <input
                          type="text"
                          placeholder={pageContent?.couponInputPlaceholderText || "Enter code"}
                          value={coupon}
                          onChange={(e) => setCoupon(e.target.value.toUpperCase())}
                          className="w-full h-[50px] rounded-full border border-[#58585A] bg-transparent px-6 outline-none text-[16px]"
                        />
                        {couponError && <p className="text-red-500 text-sm pl-4">{couponError}</p>}
                        {couponData && <p className="text-green-500 text-sm pl-4">Coupon applied! Save ${getDiscountAmount()}</p>}
                      </div>
                      <button
                        disabled={!coupon.trim() || isVerifyingCoupon || !!couponData}
                        onClick={handleApplyCoupon}
                        className={`w-full h-[50px] rounded-full mt-3 text-[16px] transition-all duration-300
                  ${coupon.trim() && !isVerifyingCoupon && !couponData
                            ? "bg-[#0097dc] text-white cursor-pointer"
                            : "bg-[#d9d9d9] text-[#999] cursor-not-allowed"
                          }`}
                      >
                        {isVerifyingCoupon ? "Applying..." : couponData ? "Applied" : (pageContent?.couponApplyButtonText || "Apply")}
                      </button>
                    </div>
                  )}
                </div>

                {/* 5. Payment Methods */}
                <div>
                  <h3 className="text-[20px] text-[#58585A] font-light mb-2 lg:mb-5">
                    {pageContent?.paymentSectionTitleText?.replace(/^4\./, '5.') || "5. Choose payment method"}
                  </h3>
                  <div className="flex flex-col gap-5 payment-box">
                    {!registerOnly && (
                      <>
                        {/* Switcher: all payment methods grouped at the top */}
                        {/* One method per row on phones: the card label plus the
                        Apple/Google marks do not fit on a ~360px line, and
                        wrapping left "Credit / Debit Card" and G Pay sharing a
                        row with Apple Pay pushed underneath. From sm up there is
                        room, so it goes back to the single wrapping row. */}
                        <div className="flex flex-col items-start gap-3 sm:flex-row sm:flex-wrap sm:items-center sm:gap-x-6 sm:gap-y-3">
                          <label className="flex items-center gap-3 text-[20px] text-[#58585A] font-light cursor-pointer">
                            <input type="radio" name="payment" className="w-5 h-5" checked={paymentMethod === "card"} onChange={() => setPaymentMethod("card")} />
                            {pageContent?.paymentByCardText || "By card"}
                          </label>

                          {/* ONLY show Apple Pay if available */}
                          {walletAvailability.applePay && (
                            <label className="flex items-center gap-3 text-[20px] text-[#58585A] font-light cursor-pointer">
                              <input type="radio" name="payment" className="w-5 h-5" checked={paymentMethod === "apple"} onChange={() => setPaymentMethod("apple")} />
                              {/* Official Apple Pay acceptance mark (SVG) — sharp at any
                              density, unlike the 138x48 PNG it replaces.

                              NOTE: this is still the BORDERED variant, because the
                              Marketing kit download only contained the mark, not
                              the logo. Its frame costs ~40% of the height, so at
                              Google's 23px the glyph inside would be tiny; 30px
                              keeps it legible while staying close enough that the
                              two do not look mismatched. Swap in Apple_Pay_Logo_*
                              when available and drop this to h-[23px] to match. */}
                              <Image src={withCDN("/class-registration/Apple_Pay_Mark_RGB_041619.svg")} alt="Apple Pay" width={166} height={106} className="h-[30px] w-auto" priority={true} />
                            </label>
                          )}

                          {walletAvailability.googlePay && (
                            <label className="flex items-center gap-3 text-[20px] text-[#58585A] font-light cursor-pointer">
                              <input type="radio" name="payment" className="w-5 h-5" checked={paymentMethod === "google"} onChange={() => setPaymentMethod("google")} />
                              {/* Official Google Pay wordmark, LIGHT-background variant.
                              Google names these after the button theme, not the ink:
                              dark_gpay is for the black button and its "Pay" is
                              #FFF, so on this white row only the coloured G showed.
                              This one uses #5F6368 grey and stays legible.

                              A viewBox was added (Google ships neither variant with
                              one), so w-auto can derive the 41:17 ratio and it
                              scales cleanly. At 2.41 that ratio matches the 128x52
                              PNG this replaces, so the row keeps its original
                              proportions — now vector, so sharp at any density. */}
                              <Image src={withCDN("/class-registration/gpay-wordmark-light.svg")} alt="Google Pay" width={41} height={17} className="h-[23px] w-auto" priority={true} />
                            </label>
                          )}

                          {walletAvailability.link && (
                            <label className="flex items-center gap-3 text-[20px] text-[#58585A] font-light cursor-pointer">
                              <input type="radio" name="payment" className="w-5 h-5" checked={paymentMethod === "link"} onChange={() => setPaymentMethod("link")} />
                              <span className="inline-flex items-center gap-2 bg-[#33ddb3] text-black text-[14px] font-semibold px-3 py-1 rounded-md">Link</span>
                            </label>
                          )}
                        </div>

                        {/* Selected method's details, shown below the switcher */}
                        {paymentMethod === "card" && (
                          <StripePaymentFields
                            cardName={cardName}
                            setCardName={setCardName}
                            saveCard={saveCard}
                            setSaveCard={setSaveCard}
                            error={paymentError}
                            onCardChange={(complete) => setIsCardComplete(complete)}
                          />
                        )}

                        {paymentMethod === "apple" && walletAvailability.applePay && (
                          <StripeWalletFields
                            amount={amountDueNow}
                            label="Class Registration"
                            onPaymentAuth={handleWalletPaymentAuth}
                          />
                        )}

                        {paymentMethod === "google" && walletAvailability.googlePay && (
                          <StripeWalletFields
                            amount={amountDueNow}
                            label="Class Registration"
                            onPaymentAuth={handleWalletPaymentAuth}
                          />
                        )}

                        {paymentMethod === "link" && walletAvailability.link && (
                          <StripeWalletFields
                            amount={amountDueNow}
                            label="Class Registration"
                            onPaymentAuth={handleWalletPaymentAuth}
                          />
                        )}
                      </>
                    )}

                    {registerOnly && (
                      <label className="flex items-center gap-3 text-[20px] text-[#58585A] font-light">
                        <input type="radio" name="payment" className="w-5 h-5" checked={paymentMethod === "later"} onChange={() => setPaymentMethod("later")} />
                        {pageContent?.paymentPayLaterText || "Pay later (we will contact you for more details)"}
                      </label>
                    )}
                  </div>
                </div>
              </>
            )}
          </div>

          {errors.form && (
            <p className="text-red-500 text-[16px] mt-4 text-center font-medium">{errors.form}</p>
          )}
          {paymentError && paymentMethod !== "card" && (
            <p className="text-red-500 text-[16px] mt-4 text-center font-medium">{paymentError}</p>
          )}

          {/* Policy — shown ABOVE the Register & Pay button */}
          <div
            // items-start (not items-center): on mobile the label wraps to two
            // lines, and centering would float the box between them instead of
            // lining it up with the first line.
            //
            // Horizontal alignment depends on whether there is a payment block
            // to line up with. payer_id "2" hides sections 4 and 5 entirely
            // (see the guard above), so there is no "Save my card details"
            // checkbox to share a left edge with and the row was left stranded
            // against the edge — centred it reads as belonging to the button.
            // With payment shown, justify-start + px-1 keeps the two checkboxes
            // on one left edge, as before.
            //
            // Only from md up: on mobile the label wraps to two lines and
            // centring would ragged-edge it, so it stays left there.
            className={`flex items-start justify-start px-1 text-[16px] mt-[20px] mb-2 cursor-pointer ${registerOnly ? "policy-row-centered" : ""
              }`}
            onClick={() => {
              setAgreed(!agreed);
              if (!agreed && errors.policy) {
                setErrors(prev => { const newErrors = { ...prev }; delete newErrors.policy; return newErrors; });
              }
            }}
          >
            {/* mt-[2px] optically centres the box against the first line of
                the 16px/1.5 label rather than its cap height. */}
            <div className={`w-[20px] h-[20px] md:w-[25px] md:h-[25px] mt-[2px] border ${errors.policy ? 'border-red-500' : 'border-[#58585A]'} rounded-[6px] mr-[10px] flex-shrink-0 flex items-center justify-center transition-all duration-200`}>
              <div className={`w-[12px] h-[12px] md:w-[15px] md:h-[15px] rounded-[4px] transition-all duration-200 ${agreed ? "bg-[#0097DC]" : "bg-transparent"}`} />
            </div>
            <span className="text-[#58585A] text-[16px] font-light text-left leading-[24px]">
              {pageContent?.policyAgreementPrefixText || "I agree with the"}{" "}
              <a
                className="text-[#0097DC] cursor-pointer hover:underline"
                onClick={(e) => { e.stopPropagation(); openPrivacyPolicy(); }}
              >
                {pageContent?.privacyPolicyLinkText || "Privacy Policy"}
              </a>
              {" and "}
              <a
                className="text-[#0097DC] cursor-pointer hover:underline"
                onClick={(e) => { e.stopPropagation(); openTermsOfUse(); }}
              >
                {pageContent?.termsOfUseLinkText || "Terms of Use"}
              </a>
            </span>
          </div>
          {errors.policy && (
            <p className="text-red-500 text-[14px] mt-1 mb-2 text-center">{errors.policy}</p>
          )}

          <button
            onClick={handleSubmit}
            disabled={isSubmitting || isProcessingPayment || !isFormFilled}
            className="mt-4 h-[50px] w-full md:w-[70%] mx-auto tracking-[1px] rounded-full bg-[#0097DC] text-[16px] md:text-[16px] font-light text-white outline-none transition-all hover:bg-[#0097DC] hover:shadow-[10px_10px_14px_#0000000D] active:shadow-[10px_10px_14px_#0000000D]  active:bg-[#0084C1] disabled:bg-[#e0e0e0] disabled:text-[#58585A] flex items-center justify-center max-[375px]:text-[12px] cursor-pointer md:gap-[6px] submit-btn"
          >
            {isSubmitting || isProcessingPayment ? (
              <Loader2 className="w-5 h-5 mr-2 animate-spin shrink-0" aria-hidden />
            ) : (
              <Image
                src={withCDN("/gear.png")}
                alt="Gear"
                width={20}
                height={20}
                className="w-[20px] h-[20px] mr-2 shrink-0"
                priority={true}
              />
            )}

            {isSubmitting || isProcessingPayment ? (
              isProcessingPayment ? "Verifying payment…" : "Processing…"
            ) : paymentMethod === "later" ? (
              pageContent?.ctaPayLaterButtonText || "Register and pay later") : (
              <>
                Register and pay ${formatAmount(displayPaymentAmount)}

                {paymentPlans?.[0]?.due_date && (
                  <span className="hidden md:inline">
                    {" "}
                    for{" "}
                    {new Date(paymentPlans[0].due_date).toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" })}
                  </span>
                )}
              </>
            )}
          </button>
        </div>

        {/*===========SIDEBAR=============*/}
        {classDetails && (
          <RegistrationSidebar
            classDetails={classDetails}
            paymentPlans={paymentPlans}
            finalPrice={amountDueNow}
            originalPrice={perUnitPrice}
            totalProgramPrice={totalClassValue}
            pageContent={pageContent}
            displayPaymentAmount={amountDueNow}
          />
        )}
      </div>

      <PrivacyPolicyModal
        isOpen={isPrivacyOpen}
        onClose={() => setIsPrivacyOpen(false)}
        heading={privacyContent?.heading}
        effectiveDate={privacyContent?.effectiveDate}
        content={privacyContent?.content}
        isLoading={isPrivacyLoading}
        linkLabel={pageContent?.privacyPolicyLinkText || "Privacy Policy"}
      />

      <PrivacyPolicyModal
        isOpen={isTermsOpen}
        onClose={() => setIsTermsOpen(false)}
        heading={termsContent?.heading}
        effectiveDate={termsContent?.effectiveDate}
        content={termsContent?.content}
        isLoading={isTermsLoading}
        linkLabel={pageContent?.termsOfUseLinkText || "Terms of Use"}
      />
    </section>
  );
}