"use client";

import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
import { motion, AnimatePresence } from "framer-motion";
import { X, Loader2 } from "lucide-react";
import Image from "next/image";
import { useSearchParams } from "next/navigation";
import { withCDN } from "@/src/lib/utils";
import { useLanguage } from "@/src/lib/context/LanguageContext";
import { getFormsAction } from "@/src/lib/actions/formsAction";
import { submitFormAction } from "@/src/lib/actions/submitFormAction";
import { DynamicFormStep, getFieldKey } from "@/src/components/layout/form/FormRenderer";
import type { Form } from "@/src/lib/services/formsService";

interface ContactUsModalProps {
  isOpen: boolean;
  onClose: () => void;
  /** Fallback heading if the fetched form has no name (defaults to "Contact Us"). */
  heading?: string;
}

// The backend "Contact Us" form is fetched/submitted through the same dynamic
// form pipeline as every other form — by this page slug.
const CONTACT_SLUG = "contact-us";

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex =
  /^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,5}[-\s\.]?[0-9]{1,4}$/;

type DynamicStep = 1 | 2 | 3 | 4 | 5;

export default function ContactUsModal({
  isOpen,
  onClose,
  heading = "Contact Us",
}: ContactUsModalProps) {
  const [mounted, setMounted] = useState(false);

  const { currentLanguage } = useLanguage();
  const searchParams = useSearchParams();
  const franchiseeId = searchParams.get("franchiseeId");

  // Fetched form definition (same shape used by Footer-Form / registration).
  const [form, setForm] = useState<Form | null>(null);
  const [loadingForm, setLoadingForm] = useState(false);
  const [formFetched, setFormFetched] = useState(false);

  // Dynamic field state, keyed the same way the shared renderer expects
  // (getFieldKey(stepOrder, fieldName)).
  const [step, setStep] = useState<DynamicStep>(1);
  const [formData, setFormData] = useState<Record<string, string | boolean>>({});
  const [formIds, setFormIds] = useState<Record<string, string>>({});
  const [errors, setErrors] = useState<Record<string, string>>({});

  const [isSubmitting, setIsSubmitting] = useState(false);
  const [submitError, setSubmitError] = useState("");
  const [submitted, setSubmitted] = useState(false);
  const [successMessage, setSuccessMessage] = useState("");

  useEffect(() => {
    setMounted(true);
  }, []);

  // NOTE: we deliberately do NOT lock body scroll here. This site scrolls the
  // window while `body { height: 100% }` (globals.css) is set, so every body
  // overflow/position lock collapses the layout and drops the scroll offset —
  // making the page jump to the top on open/close. The modal's backdrop and
  // dialog are both `fixed`, so they stay put on screen without a lock, and
  // leaving the scroll position untouched means no jump.

  useEffect(() => {
    if (!isOpen) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") onClose();
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [isOpen, onClose]);

  // Reset the entered values / result each time the popup opens.
  useEffect(() => {
    if (isOpen) {
      setStep(1);
      setFormData({});
      setFormIds({});
      setErrors({});
      setIsSubmitting(false);
      setSubmitError("");
      setSubmitted(false);
      setSuccessMessage("");
    }
  }, [isOpen]);

  // Fetch the Contact Us form once, the first time the popup is opened.
  // NOTE: `loadingForm` must NOT be in the dependency array — setting it would
  // re-run this effect and its cleanup would cancel the in-flight request, so
  // the `finally` never clears the loading state (stuck on "Loading…").
  useEffect(() => {
    if (!isOpen || formFetched) return;

    let cancelled = false;
    setLoadingForm(true);
    (async () => {
      try {
        const res = await getFormsAction(franchiseeId, currentLanguage, CONTACT_SLUG);
        if (!cancelled) setForm(res.success ? res.data : null);
      } catch {
        if (!cancelled) setForm(null);
      } finally {
        if (!cancelled) {
          setLoadingForm(false);
          setFormFetched(true);
        }
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [isOpen, formFetched, franchiseeId, currentLanguage]);

  const formSteps = form?.fields?.steps || [];
  const totalSteps = formSteps.length;
  const currentFormStep = formSteps[step - 1] || null;

  const ctaText =
    (!Array.isArray(form?.fields?.cta) && form?.fields?.cta?.text) || "Send";
  const agreementText =
    form?.fields?.agree?.text || "I agree with the Data collection policy";

  // Same validation rules as the shared form (Footer-Form). The strict
  // letters-only rule only applies to name-like fields so message/other text
  // fields accept punctuation.
  const validateField = (
    fieldType: string,
    value: string,
    fieldName: string,
    isRequired: boolean,
    stepOrder: number | string
  ) => {
    const errorKey = getFieldKey(stepOrder, fieldName);
    // Prefer the human placeholder ("Name", "Email") over the raw field id
    // ("Text Field", "Email Field") in messages.
    const label =
      currentFormStep?.fields.find((f) => f.field === fieldName)?.placeholder ||
      fieldName;
    let message = "";

    if (!value && isRequired) {
      message = `${label} is required`;
    } else if (value && fieldType === "email" && !emailRegex.test(value)) {
      message = "Please enter a valid email address";
    } else if (value && fieldType === "number" && !phoneRegex.test(value)) {
      message = "Please enter a valid phone number";
    } else if (
      value &&
      fieldType === "text" &&
      /name/i.test(fieldName) &&
      !/^[a-zA-Z\s\-']*$/.test(value)
    ) {
      message = `${label} should only contain letters, spaces, and hyphens`;
    }

    setErrors((prev) => ({ ...prev, [errorKey]: message }));
  };

  // The agreement checkbox only shows (and is enforced) on the last step, next
  // to the Send button.
  const agreeField = form?.fields?.agree;
  const showAgreement = !!agreeField && step === totalSteps;

  const isCurrentStepValid = (): boolean => {
    if (!currentFormStep) return false;

    const fieldsValid = currentFormStep.fields.every((field) => {
      const key = getFieldKey(currentFormStep.order, field.field);
      const value = formData[key];

      if (field.required && (!value || String(value).trim() === "")) return false;
      if (value) {
        const v = String(value);
        if (field.type === "email" && !emailRegex.test(v)) return false;
        if (field.type === "number" && !phoneRegex.test(v)) return false;
        if (field.type === "text" && /name/i.test(field.field) && !/^[a-zA-Z\s\-']*$/.test(v))
          return false;
      }
      if (errors[key]) return false;
      return true;
    });

    const agreeValid =
      showAgreement && agreeField?.required
        ? !!formData[`agree_step_${currentFormStep.order}`]
        : true;

    return fieldsValid && agreeValid;
  };

  const normalizeFieldName = (fieldName: string): string =>
    fieldName
      .toLowerCase()
      .replace(/['']/g, "")
      .replace(/\s+/g, "_")
      .replace(/[^a-z0-9_]/g, "");

  // Shape the entered values into the per-step array the backend expects —
  // identical to Footer-Form's formatFormDataForSubmission.
  const formatFormDataForSubmission = (): Array<Record<string, string>> => {
    return formSteps.map((stepData, index) => {
      const stepEntry: Record<string, string> = {};
      const stepNumber = stepData.order || index + 1;
      stepEntry[`step_${stepNumber}`] = stepData.heading
        ? stepData.heading.toLowerCase().replace(/\s+/g, "_")
        : `step_${stepNumber}`;

      stepData.fields.forEach((field) => {
        const value = formData[getFieldKey(stepNumber, field.field)];
        if (value !== undefined && value !== "") {
          stepEntry[normalizeFieldName(field.field)] = String(value);
        }
      });

      return stepEntry;
    });
  };

  const handleConfirm = async () => {
    if (!isCurrentStepValid()) return;

    if (step < totalSteps) {
      setStep((step + 1) as DynamicStep);
      return;
    }

    setIsSubmitting(true);
    setSubmitError("");
    try {
      const response = await submitFormAction({
        form_id: form?.id || "",
        form_data: formatFormDataForSubmission(),
        slug: CONTACT_SLUG,
      });

      if (response.status) {
        setSuccessMessage(
          form?.form_setting?.success_message ||
            response.message ||
            "We will contact you as soon as possible"
        );
        setSubmitted(true);
      } else {
        setSubmitError(response.message || "Failed to send your message.");
      }
    } catch {
      setSubmitError("An error occurred while sending your message.");
    } finally {
      setIsSubmitting(false);
    }
  };

  const successImage =
    form?.form_setting?.featured_image ||
    withCDN("/class-registration/photo%20(4)%20(2).png");

  const modal = (
    <AnimatePresence>
      {isOpen && (
        <div className="fixed inset-0 z-[2147483647] overflow-y-auto">
          {/* Backdrop */}
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            onClick={onClose}
            className="fixed inset-0 bg-[#00294A]/60 backdrop-blur-[3px]"
          />

          {/* Centering wrapper */}
          <div className="relative min-h-full flex items-start sm:items-center justify-center p-0 sm:p-4 sm:py-10">
            <motion.div
              initial={{ opacity: 0, y: 24, scale: 0.98 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              exit={{ opacity: 0, y: 24, scale: 0.98 }}
              transition={{ type: "spring", damping: 26, stiffness: 320 }}
              onClick={(e) => e.stopPropagation()}
              role="dialog"
              aria-modal="true"
              aria-label={form?.name || heading}
              className="relative w-full sm:max-w-[440px] min-h-[100dvh] sm:min-h-0 bg-white sm:rounded-[24px] shadow-[0_30px_80px_-20px_rgba(0,41,74,0.55)] ring-1 ring-black/5 overflow-hidden flex flex-col"
            >
              {/* Close */}
              <button
                type="button"
                onClick={onClose}
                aria-label="Close"
                className="absolute top-4 right-4 z-20 grid place-items-center w-9 h-9 rounded-full bg-[#F1F4F7] hover:bg-[#E3E8ED] text-[#5A6672] transition-colors cursor-pointer"
              >
                <X size={18} />
              </button>

              {submitted ? (
                /* ---------- Thank you state ---------- */
                <div className="flex flex-col items-center px-6 pt-10 pb-8 text-center">
                  <h2 className="text-[30px] font-[700] text-[#58585A] uppercase tracking-[0.01em] leading-tight">
                    Thank You!
                  </h2>
                  <p className="mt-2 text-[16px] text-[#6B7280]">{successMessage}</p>
                  <div className="mt-6 w-full overflow-hidden rounded-[16px]">
                    <Image
                      src={successImage}
                      alt="Thank you"
                      width={440}
                      height={300}
                      className="w-full h-auto object-cover"
                    />
                  </div>
                  {/* <button
                    type="button"
                    onClick={onClose}
                    className="mt-7 px-8 py-2.5 rounded-full bg-gradient-to-r from-[#0097DC] to-[#0077B6] text-white font-semibold text-sm hover:shadow-[0_8px_20px_-6px_rgba(0,151,220,0.7)] active:scale-[0.98] transition-all cursor-pointer"
                  >
                    Close
                  </button>*/}
                </div>
              ) : loadingForm ? (
                /* ---------- Loading ---------- */
                <div className="flex flex-col items-center justify-center gap-3 py-24 text-[#0097DC]">
                  <Loader2 className="animate-spin" size={30} />
                  <span className="text-sm text-[#6B7280]">Loading…</span>
                </div>
              ) : !currentFormStep ? (
                /* ---------- No form configured ---------- */
                <div className="flex flex-col items-center justify-center gap-2 px-6 py-24 text-center">
                  <h2 className="text-[22px] font-[700] text-[#58585A] uppercase">
                    {heading}
                  </h2>
                  <p className="text-[14px] text-[#6B7280]">
                    The contact form is not available right now. Please try again later.
                  </p>
                </div>
              ) : (
                /* ---------- Form state ---------- */
                <div className="px-6 pt-9 pb-8">
                  <h2 className="text-center text-[28px] font-[700] text-[#58585A] uppercase tracking-[0.01em] leading-tight">
                    {form?.name || heading}
                  </h2>
                  <p className="text-center mt-1 mb-6 text-[15px] text-[#6B7280]">
                    {form?.description || "Please fill in the form"}
                  </p>

                  {totalSteps > 1 && (
                    <div className="flex items-center gap-[3px] mt-3 w-full justify-center h-[4px]">
                      {Array.from({ length: totalSteps }, (_, i) => i + 1).map((i) => (
                        <div
                          key={i}
                          className={`h-[4px] w-full rounded-[10px] transition-all ${
                            i < step
                              ? "bg-[#00A538]"
                              : i === step
                              ? "bg-[#0097DC]"
                              : "bg-[#BDBDBD]"
                          }`}
                        />
                      ))}
                    </div>
                  )}

                  {submitError && (
                    <div className="mt-4 w-full p-3 rounded-lg text-center text-sm bg-red-100 text-red-700 border border-red-300">
                      {submitError}
                    </div>
                  )}

                  <DynamicFormStep
                    step={currentFormStep}
                    formData={formData}
                    formIds={formIds}
                    errors={errors}
                    onChange={(fieldName, value, fieldId) => {
                      // Agreement keys ("agree_step_N") are already scoped by the
                      // renderer — store them as-is, everything else gets scoped.
                      const isAgreementKey = fieldName.startsWith("agree_step_");
                      const key = isAgreementKey
                        ? fieldName
                        : getFieldKey(currentFormStep.order, fieldName);
                      setFormData((prev) => ({ ...prev, [key]: value }));
                      if (fieldId !== undefined && typeof value === "string") {
                        setFormIds((prev) => ({ ...prev, [key]: fieldId }));
                      }
                      if (typeof value === "string" && !isAgreementKey) {
                        validateField(
                          currentFormStep.fields.find((f) => f.field === fieldName)?.type ||
                            "text",
                          value,
                          fieldName,
                          false,
                          currentFormStep.order
                        );
                      }
                    }}
                    onValidate={(fieldType, value, fieldName, isRequired) =>
                      validateField(
                        fieldType,
                        value,
                        fieldName,
                        !!isRequired,
                        currentFormStep.order
                      )
                    }
                    agreementText={agreementText}
                    policyFranchiseeId={franchiseeId}
                    policyLanguage={currentLanguage}
                    valid={isCurrentStepValid()}
                    onConfirm={handleConfirm}
                    onGoBack={() => setStep((step - 1) as DynamicStep)}
                    isSubmitting={isSubmitting}
                    showGoBack={step > 1}
                    hideStepHeading
                    showAgreement={showAgreement}
                    agreementPrivacyHref="/privacy-policy"
                    agreementTermsHref="/terms-of-use"
                    confirmText={step === totalSteps ? ctaText : "Next"}
                    totalSteps={totalSteps}
                  />
                </div>
              )}
            </motion.div>
          </div>
        </div>
      )}
    </AnimatePresence>
  );

  if (!mounted) return null;
  return createPortal(modal, document.body);
}
