"use client";

import Link from "next/link";
import { useState } from "react";
import { usePathname, useRouter } from "next/navigation";
import {
  ArrowLeft,
  ArrowRight,
  Building2,
  ChevronDown,
  LoaderCircle,
  Mail,
  MapPin,
  Phone,
  Ticket,
  UserRound,
} from "lucide-react";

import { authCopy } from "@/components/auth/auth-copy";
import OtpInput from "@/components/auth/OtpInput";
import NumericPhoneInput from "@/components/forms/NumericPhoneInput";
import { storeAuthSession } from "@/features/auth/auth-storage";
import {
  useRegisterMutation,
  useVerifyOtpMutation,
} from "@/features/auth/auth.hooks";
import {
  phoneSchema,
  registerSchema,
  verifyOtpSchema,
} from "@/features/auth/auth.schemas";
import {
  ApiError,
  getApiErrorMessage,
  normalizeApiError,
} from "@/lib/api/api-error";
import { showErrorAlert, showSuccessAlert } from "@/lib/alerts";
import {
  getFirstFormError,
  getFormErrors,
  type FormErrors,
} from "@/lib/form-errors";
import type { Locale } from "@/lib/locales";
import {
  defaultDemoProduct,
  getProductId,
  inferProductSlug,
} from "@/lib/product-map";
import type { ProductSlug } from "@/lib/routes";

const baseFieldClass =
  "h-11 w-full rounded-lg border bg-white px-10 text-[13px] text-[#253052] outline-none transition placeholder:text-[#a7b0c0]";

const normalFieldClass =
  "border-[#dde4f1] focus:border-[#6b72f2] focus:ring-3 focus:ring-[#e9eaff]";

const errorFieldClass =
  "border-rose-400 focus:border-rose-500 focus:ring-3 focus:ring-rose-100";

const BUILDPRO_DASHBOARD_URL =
  "https://sitsoftwares.co.in/Builderpro/dashboard.php";

const SOCIETYPRO_DASHBOARD_URL =
  "https://sitsoftwares.co.in/Society_Management_System/society_onboarding_form.php";

const PUREESTATE_DASHBOARD_URL =
  "https://sitsoftwares.co.in/Estate_Ninja/main_dashboard.php";

type RegisterStep = 1 | 2 | 3;
type TouchedFields = Record<string, boolean>;

export default function RegisterForm({
  locale,
  loginHref,
  productSlug,
}: {
  locale: Locale;
  loginHref: string;
  productSlug?: ProductSlug;
}) {
  const copy = authCopy[locale];
  const pathname = usePathname();
  const router = useRouter();
  const verifyOtpMutation = useVerifyOtpMutation();
  const registerMutation = useRegisterMutation();

  const [errors, setErrors] = useState<FormErrors>({});
  const [touchedFields, setTouchedFields] = useState<TouchedFields>({});
  const [submitted, setSubmitted] = useState(false);
  const [step, setStep] = useState<RegisterStep>(1);
  const [pendingPhone, setPendingPhone] = useState<string | null>(null);
  const [verifiedPhone, setVerifiedPhone] = useState<string | null>(null);
  const [referralCode, setReferralCode] = useState("");

  const productId = getProductId(
    productSlug ?? inferProductSlug(pathname) ?? defaultDemoProduct,
  );

  const currentProductSlug =
    productSlug ?? inferProductSlug(pathname) ?? defaultDemoProduct;

  const isSocietyRegister = currentProductSlug === "societypro";

  function getCurrentStepErrors(form: HTMLFormElement): FormErrors {
    const values = Object.fromEntries(new FormData(form));

    if (step === 1) {
      return getPhoneStepErrors(values.phone);
    }

    const parsed =
      step === 2
        ? verifyOtpSchema.safeParse({
            ...values,
            phone: pendingPhone ?? "",
          })
        : registerSchema.safeParse({
            ...values,
            phone: verifiedPhone ?? "",
          });

    return parsed.success ? {} : getFormErrors(parsed.error);
  }

  function getVisibleErrors(
    allErrors: FormErrors,
    nextTouchedFields: TouchedFields,
    shouldShowAll: boolean,
  ): FormErrors {
    if (shouldShowAll) return allErrors;

    return Object.fromEntries(
      Object.entries(allErrors).filter(
        ([fieldName]) => nextTouchedFields[fieldName],
      ),
    ) as FormErrors;
  }

  function handleRealtimeValidation(event: React.FormEvent<HTMLFormElement>) {
    const target = event.target as
      HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;

    const fieldName = target.name;

    if (!fieldName) return;

    const nextTouchedFields = {
      ...touchedFields,
      [fieldName]: true,
    };

    const allErrors = getCurrentStepErrors(event.currentTarget);

    setTouchedFields(nextTouchedFields);
    setErrors(getVisibleErrors(allErrors, nextTouchedFields, submitted));
  }

  function resetValidation() {
    setErrors({});
    setTouchedFields({});
    setSubmitted(false);
  }

  async function handleMobileSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();

    setSubmitted(true);

    const parsed = phoneSchema.safeParse(
      new FormData(event.currentTarget).get("phone"),
    );

    if (!parsed.success) {
      const formErrors = getPhoneStepErrors(
        new FormData(event.currentTarget).get("phone"),
      );

      setErrors(formErrors);
      await showErrorAlert(
        formErrors.phone?.[0] ?? "Enter a valid mobile number.",
        {
          locale,
        },
      );
      return;
    }

    setPendingPhone(parsed.data);
    setVerifiedPhone(null);
    setStep(2);
    resetValidation();
  }
  async function handleVerifyOtp(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();

    if (verifyOtpMutation.isPending) return;

    setSubmitted(true);

    const parsed = verifyOtpSchema.safeParse({
      ...Object.fromEntries(new FormData(event.currentTarget)),
      phone: pendingPhone ?? "",
    });

    if (!parsed.success) {
      const formErrors = getFormErrors(parsed.error);

      setErrors(formErrors);
      await showErrorAlert(getFirstFormError(parsed.error), { locale });
      return;
    }

    resetValidation();

    try {
      const verification = await verifyOtpMutation.mutateAsync(parsed.data);

      if (verification.status !== "success" || !verification.verified) {
        throw new ApiError(verification.message || "OTP verification failed.");
      }

      setVerifiedPhone(parsed.data.phone);
      await showSuccessAlert(verification.message || copy.otpVerified, {
        autoClose: true,
        locale,
      });
      setStep(3);
      resetValidation();
    } catch (error) {
      const apiError = normalizeApiError(error, locale);
      await showErrorAlert(getApiErrorMessage(apiError, locale), {
        locale,
      });
    }
  }

  async function handleRegister(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();

    if (registerMutation.isPending) return;

    if (!verifiedPhone) {
      setStep(1);
      resetValidation();
      await showErrorAlert("Please verify your mobile number first.", {
        locale,
      });
      return;
    }

    setSubmitted(true);

    const parsed = registerSchema.safeParse({
      ...Object.fromEntries(new FormData(event.currentTarget)),
      phone: verifiedPhone,
    });

    if (!parsed.success) {
      const formErrors = getFormErrors(parsed.error);

      setErrors(formErrors);
      await showErrorAlert(getFirstFormError(parsed.error), { locale });
      return;
    }

    resetValidation();

    try {
      const response = await registerMutation.mutateAsync({
        ...parsed.data,
        product_id: productId,
      });

      storeAuthSession(response);

      await showSuccessAlert(response.message, { autoClose: true, locale });
      redirectAfterRegister(productId, router.push);
    } catch (error) {
      const apiError = normalizeApiError(error, locale);
      await showErrorAlert(getApiErrorMessage(apiError, locale), {
        locale,
      });
    }
  }

  return (
    <form
      noValidate
      onBlur={handleRealtimeValidation}
      onChange={handleRealtimeValidation}
      onSubmit={
        step === 1
          ? handleMobileSubmit
          : step === 2
            ? handleVerifyOtp
            : handleRegister
      }
      className="rounded-3xl border border-[#e2e7f2] bg-white p-5 shadow-[0_18px_50px_rgba(40,55,105,0.1)] sm:p-7"
    >
      <RegisterStepIndicator step={step} />

      {step === 1 ? (
        <>
          <div className="mt-5 grid gap-3.5">
            <IconField
              autoComplete="tel"
              defaultValue={pendingPhone ?? verifiedPhone ?? undefined}
              error={errors.phone}
              icon={Phone}
              label={copy.phone}
              name="phone"
              numericPhone
              required
            />
          </div>

          <button
            type="submit"
            className="mt-5 inline-flex h-12 w-full items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-[#5264ee] to-[#6555e9] px-5 text-[13px] font-extrabold text-white shadow-[0_8px_18px_rgba(93,91,238,0.24)] transition hover:-translate-y-0.5"
          >
            <ArrowRight size={16} />
            Continue to OTP
          </button>
        </>
      ) : step === 2 ? (
        <>
          <input type="hidden" name="phone" value={pendingPhone ?? ""} />

          <div className="mt-5 rounded-xl border border-[#dde4f1] bg-[#f8f9ff] px-4 py-3 text-[12px] font-bold text-[#34405d]">
            {copy.phone}: <span className="text-[#5c66df]">{pendingPhone}</span>
          </div>

          <div className="mt-5 grid gap-3.5">
            <OtpInput error={errors.otp} label={copy.otp} name="otp" />
          </div>

          <div className="mt-5 flex gap-3">
            <button
              type="button"
              disabled={verifyOtpMutation.isPending}
              onClick={() => {
                resetValidation();
                setStep(1);
              }}
              className="inline-flex h-12 items-center justify-center gap-2 rounded-lg border border-[#dde4f1] bg-white px-5 text-[13px] font-extrabold text-[#5c66df] transition hover:bg-[#f8f9ff] disabled:cursor-wait disabled:opacity-70"
            >
              <ArrowLeft size={16} />
              Back
            </button>

            <button
              type="submit"
              disabled={verifyOtpMutation.isPending}
              className="inline-flex h-12 flex-1 items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-[#5264ee] to-[#6555e9] px-5 text-[13px] font-extrabold text-white shadow-[0_8px_18px_rgba(93,91,238,0.24)] transition hover:-translate-y-0.5 disabled:cursor-wait disabled:opacity-70"
            >
              {verifyOtpMutation.isPending ? (
                <LoaderCircle size={16} className="animate-spin" />
              ) : (
                <ArrowRight size={16} />
              )}

              {verifyOtpMutation.isPending ? copy.verifyingOtp : "Verify OTP"}
            </button>
          </div>
        </>
      ) : (
        <>
          <div className="mt-5 grid gap-3.5 sm:grid-cols-2">
            <IconField
              autoComplete="name"
              error={errors.full_name}
              icon={UserRound}
              label={copy.name}
              name="full_name"
              required
            />

            <IconField
              autoComplete="email"
              error={errors.email}
              icon={Mail}
              label={copy.email}
              name="email"
              required
              type="email"
            />

            <IconField
              autoComplete="organization"
              error={errors.company_name}
              icon={Building2}
              label={isSocietyRegister ? copy.societyName : copy.company}
              name="company_name"
              required
            />

            {isSocietyRegister ? (
              <SelectField
                error={errors.society_type}
                label={copy.typeOfSociety}
                name="society_type"
                options={societyTypeOptions[locale]}
                placeholder={copy.chooseSocietyType}
              />
            ) : null}

            <IconField
              autoComplete="address-level2"
              error={errors.city}
              icon={MapPin}
              label={copy.city}
              name="city"
              required
            />

            <IconField
              autoComplete="address-level1"
              error={errors.state}
              icon={MapPin}
              label={copy.state}
              name="state"
              required
            />

            <label className="block text-[12px] font-bold text-[#34405d] sm:col-span-2">
              {copy.address}

              <textarea
                name="company_address"
                required
                rows={3}
                className={`mt-1.5 w-full rounded-lg border bg-white px-3 py-3 text-[13px] text-[#253052] outline-none transition ${
                  errors.company_address?.[0]
                    ? errorFieldClass
                    : normalFieldClass
                }`}
              />

              <ErrorText errors={errors.company_address} />
            </label>

            <input
              type="hidden"
              name="has_referral"
              value={referralCode.trim() ? "yes" : "no"}
            />

            <label className="block text-[12px] font-bold text-[#34405d] sm:col-span-2">
              {copy.referralCode}

              <span className="relative mt-1.5 block">
                <Ticket
                  size={16}
                  className={`pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 ${
                    errors.referral_code?.[0]
                      ? "text-rose-500"
                      : "text-[#8b96aa]"
                  }`}
                />

                <input
                  autoComplete="off"
                  className={`${baseFieldClass} ${
                    errors.referral_code?.[0]
                      ? errorFieldClass
                      : normalFieldClass
                  }`}
                  name="referral_code"
                  type="text"
                  value={referralCode}
                  onChange={(event) => setReferralCode(event.target.value)}
                />
              </span>

              <ErrorText errors={errors.referral_code} />
            </label>
          </div>

          <div className="mt-5 flex gap-3">
            <button
              type="button"
              disabled={registerMutation.isPending}
              onClick={() => {
                resetValidation();
                setStep(2);
              }}
              className="inline-flex h-12 items-center justify-center gap-2 rounded-lg border border-[#dde4f1] bg-white px-5 text-[13px] font-extrabold text-[#5c66df] transition hover:bg-[#f8f9ff] disabled:cursor-wait disabled:opacity-70"
            >
              <ArrowLeft size={16} />
              Back
            </button>

            <button
              type="submit"
              disabled={registerMutation.isPending}
              className="inline-flex h-12 flex-1 items-center justify-center gap-2 rounded-lg bg-gradient-to-r from-[#5264ee] to-[#6555e9] px-5 text-[13px] font-extrabold text-white shadow-[0_8px_18px_rgba(93,91,238,0.24)] transition hover:-translate-y-0.5 disabled:cursor-wait disabled:opacity-70"
            >
              {registerMutation.isPending ? (
                <LoaderCircle size={16} className="animate-spin" />
              ) : (
                <ArrowRight size={16} />
              )}

              {registerMutation.isPending ? copy.registering : copy.register}
            </button>
          </div>
        </>
      )}
      <p className="mt-4 text-center text-[12px] text-[#7a869d]">
        {copy.hasAccount}{" "}
        <Link href={loginHref} className="font-extrabold text-[#5c66df]">
          {copy.signIn}
        </Link>
      </p>
    </form>
  );
}

function getPhoneStepErrors(
  value: FormDataEntryValue | null | unknown,
): FormErrors {
  const parsed = phoneSchema.safeParse(value);

  return parsed.success
    ? {}
    : { phone: parsed.error.issues.map((issue) => issue.message) };
}
function redirectAfterRegister(
  productId: number | string | undefined,
  push: (href: string) => void,
) {
  const normalizedProductId = Number(productId);

  if (normalizedProductId === 1) {
    window.location.replace(PUREESTATE_DASHBOARD_URL);
    return;
  }

  if (normalizedProductId === 2) {
    window.location.replace(BUILDPRO_DASHBOARD_URL);
    return;
  }

  if (normalizedProductId === 3) {
    window.location.replace(SOCIETYPRO_DASHBOARD_URL);
    return;
  }

  push("/");
}

function RegisterStepIndicator({ step }: { step: RegisterStep }) {
  return (
    <div className="grid gap-2 rounded-xl bg-[#f7f8ff] p-1.5 sm:grid-cols-3">
      <StepIndicatorItem active={step === 1} label="Mobile" number={1} />
      <StepIndicatorItem active={step === 2} label="OTP" number={2} />
      <StepIndicatorItem active={step === 3} label="Details" number={3} />
    </div>
  );
}

function StepIndicatorItem({
  active,
  label,
  number,
}: {
  active: boolean;
  label: string;
  number: RegisterStep;
}) {
  return (
    <div
      className={`flex items-center gap-2 rounded-lg px-3 py-2 text-[11px] font-extrabold transition ${
        active ? "bg-white text-[#5c66df] shadow-sm" : "text-[#8b96aa]"
      }`}
    >
      <span
        className={`grid h-6 w-6 place-items-center rounded-full text-[10px] ${
          active ? "bg-[#5c66df] text-white" : "bg-[#e9ecf5] text-[#8b96aa]"
        }`}
      >
        {number}
      </span>

      <span>
        Step {number}: {label}
      </span>
    </div>
  );
}

function IconField({
  autoComplete,
  defaultValue,
  error,
  icon: Icon,
  label,
  minLength,
  name,
  numericPhone = false,
  required,
  type = "text",
}: {
  autoComplete: string;
  defaultValue?: string;
  error?: string[];
  icon: typeof UserRound;
  label: string;
  minLength?: number;
  name: string;
  numericPhone?: boolean;
  required?: boolean;
  type?: string;
}) {
  const hasError = Boolean(error?.[0]);
  const fieldClass = `${baseFieldClass} ${
    hasError ? errorFieldClass : normalFieldClass
  }`;

  return (
    <label className="block text-[12px] font-bold text-[#34405d]">
      {label}

      <span className="relative mt-1.5 block">
        <Icon
          size={16}
          className={`pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 ${
            hasError ? "text-rose-500" : "text-[#8b96aa]"
          }`}
        />

        {numericPhone ? (
          <NumericPhoneInput
            autoComplete={autoComplete}
            className={fieldClass}
            defaultValue={defaultValue}
            name={name}
            required={required}
          />
        ) : (
          <input
            autoComplete={autoComplete}
            className={fieldClass}
            defaultValue={defaultValue}
            minLength={minLength}
            name={name}
            required={required}
            type={type}
          />
        )}
      </span>

      <ErrorText errors={error} />
    </label>
  );
}

function SelectField({
  error,
  label,
  name,
  options,
  placeholder,
}: {
  error?: string[];
  label: string;
  name: string;
  options: string[];
  placeholder: string;
}) {
  const hasError = Boolean(error?.[0]);
  const fieldClass = `${baseFieldClass} appearance-none ${
    hasError ? errorFieldClass : normalFieldClass
  }`;

  return (
    <label className="block text-[12px] font-bold text-[#34405d]">
      {label}

      <span className="relative mt-1.5 block">
        <Building2
          size={16}
          className={`pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 ${
            hasError ? "text-rose-500" : "text-[#8b96aa]"
          }`}
        />

        <select className={`${fieldClass} pr-9`} defaultValue="" name={name}>
          <option value="" disabled>
            {placeholder}
          </option>

          {options.map((option) => (
            <option key={option} value={option}>
              {option}
            </option>
          ))}
        </select>

        <ChevronDown
          size={16}
          className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-[#8b96aa]"
        />
      </span>

      <ErrorText errors={error} />
    </label>
  );
}

function ErrorText({ errors }: { errors?: string[] }) {
  return errors?.[0] ? (
    <span className="mt-1 block text-[11px] font-semibold text-rose-600">
      {errors[0]}
    </span>
  ) : null;
}

const societyTypeOptions = {
  en: [
    "Apartment",
    "Bungalow/villa Society",
    "Row House Society",
    "Commercial Society",
  ],
  hi: [
    "अपार्टमेंट / फ्लैट",
    "बंगला/विला सोसायटी",
    "रो हाउस सोसायटी",
    "कमर्शियल सोसायटी",
  ],
  gu: [
    "એપાર્ટમેન્ટ / ફ્લેટ",
    "બંગલો/વિલા સોસાયટી",
    "રો હાઉસ સોસાયટી",
    "કોમર્શિયલ સોસાયટી",
  ],
} satisfies Record<Locale, string[]>;
