import { useState } from "react";
import { zodResolver } from "@hookform/resolvers/zod";
import {
  Alert,
  Button,
  PasswordInput,
  SimpleGrid,
  Stack,
  TextInput,
} from "@mantine/core";
import { AlertCircle, ArrowRight } from "lucide-react";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
import { z } from "zod";

import { userType } from "@/enums/userType";
import useAuth from "@/hooks/useAuth";
import { useResendCooldown } from "@/hooks/useResendCooldown";
import type { SignupPayload } from "@/types/auth";
import AuthShell from "@/components/auth/AuthShell";
import OtpChannelStep, { OTP_LENGTH } from "@/components/auth/OtpChannelStep";
import PasswordChecklist from "@/components/auth/PasswordChecklist";
import { ControlledPhoneField, isValidPhone } from "@/components/PhoneField";
import { api } from "@/services/api";
import {
  confirmPasswordField,
  passwordField,
  samePassword,
} from "@/utils/passwordSchema";
import { extractApiError } from "@/utils/result";

const userSchema = z
  .object({
    email: z.string().email("Invalid email address"),
    phone: z
      .string()
      .min(1, "Phone number is required")
      .refine(isValidPhone, "Enter a valid phone number"),
    userType: z.string(),
    firstName: z.object({
      en: z.string().min(2, "Name is required"),
      am: z.string().nullable(),
    }),
    lastName: z.object({
      en: z.string().min(2, "Name is required"),
      am: z.string().nullable(),
    }),
    password: passwordField,
    confirmPassword: confirmPasswordField,
  })
  .refine(samePassword, {
    message: "Passwords do not match",
    path: ["confirmPassword"],
  });

type FormData = z.infer<typeof userSchema>;

export default function SignupPage() {
  const navigate = useNavigate();
  const { signup } = useAuth();
  const [error, setError] = useState<string | null>(null);

  // Two-stage signup: fill the form, then a mandatory OTP challenge before the
  // account is actually created. The code goes to BOTH the email and phone just
  // entered — one code, either delivery verifies it — so there is nothing for
  // the user to choose. The account is only created after the code is verified;
  // the OTP is a hard requirement.
  const [stage, setStage] = useState<"form" | "otp">("form");
  const [pendingData, setPendingData] = useState<FormData | null>(null);
  const [sending, setSending] = useState(false);
  const [verifying, setVerifying] = useState(false);
  const [otpCode, setOtpCode] = useState("");
  const [otpError, setOtpError] = useState<string | null>(null);
  const resendCooldown = useResendCooldown();

  const {
    register,
    handleSubmit,
    watch,
    control,
    formState: { errors },
  } = useForm<FormData>({
    resolver: zodResolver(userSchema),
    defaultValues: {
      email: "",
      phone: "",
      userType: userType.individual,
      firstName: { en: "", am: "" },
      lastName: { en: "", am: "" },
      password: "",
      confirmPassword: "",
    },
  });

  const passwordValue = watch("password") ?? "";

  // Step 1 — form is valid: make sure the email/phone aren't already
  // registered, then send a fresh code to both of them and move to the OTP
  // challenge.
  const requestOtp = async (data: FormData) => {
    setError(null);
    setSending(true);
    try {
      const availability = await api.auth.checkAvailability.call({
        email: data.email,
        phone: data.phone,
      });
      if (availability.emailTaken && availability.phoneTaken) {
        setError("An account with this email and phone number already exists.");
        return;
      }
      if (availability.emailTaken) {
        setError("An account with this email already exists.");
        return;
      }
      if (availability.phoneTaken) {
        setError("An account with this phone number already exists.");
        return;
      }

      await api.auth.sendOTP.call({ email: data.email, phone: data.phone });
      setPendingData(data);
      setOtpCode("");
      setOtpError(null);
      resendCooldown.start();
      setStage("otp");
    } catch (err) {
      setError(extractApiError(err).message);
    } finally {
      setSending(false);
    }
  };

  const resendOtp = async () => {
    if (!pendingData) return;
    setOtpError(null);
    setSending(true);
    try {
      await api.auth.sendOTP.call({
        email: pendingData.email,
        phone: pendingData.phone,
      });
      setOtpCode("");
      resendCooldown.start();
    } catch (err) {
      setOtpError(extractApiError(err).message);
    } finally {
      setSending(false);
    }
  };

  // Step 2 — verify the code, then (only on success) create the account.
  const confirmOtp = async () => {
    if (!pendingData) return;
    setOtpError(null);
    if (otpCode.trim().length !== OTP_LENGTH) {
      setOtpError(`Enter the ${OTP_LENGTH}-digit code we sent you.`);
      return;
    }
    setVerifying(true);
    try {
      await api.auth.verifyOTP.call({
        email: pendingData.email,
        phone: pendingData.phone,
        otp: otpCode.trim(),
      });
      const payload: SignupPayload = {
        email: pendingData.email,
        username: pendingData.email,
        // Already a canonical E.164 string from the phone field (e.g. +251912345678).
        phoneNumber: pendingData.phone,
        userType: pendingData.userType,
        name: {
          en: `${pendingData.firstName.en} ${pendingData.lastName.en}`,
          am: `${pendingData.firstName.en} ${pendingData.lastName.en}`,
        },
        password: pendingData.password,
        confirmPassword: pendingData.confirmPassword,
      };
      const result = await signup(payload);
      if (result.success) {
        navigate("/portal");
      } else {
        setOtpError(result.error.message);
      }
    } catch (err) {
      setOtpError(extractApiError(err).message);
    } finally {
      setVerifying(false);
    }
  };

  return (
    <AuthShell
      tagline="Smart Freight Operations"
      taglineBody="Join EDR Freight to manage shipments, track consignments, and streamline logistics workflows across Ethiopia and Djibouti."
    >
      <div className="flex w-full flex-col">
        {stage === "form" ? (
          <form
            onSubmit={handleSubmit(requestOtp)}
            className="flex w-full flex-col"
          >
            <div className="mb-4 space-y-1.5 text-center sm:mb-5">
              <h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
                Create account
              </h1>
              <p className="text-sm leading-relaxed text-gray-500">
                Register to access EDR Freight services.
              </p>
            </div>

            <Stack gap="sm">
              <SimpleGrid cols={{ base: 1, sm: 2 }} spacing="md">
                <TextInput
                  label="First name"
                  placeholder="John"
                  required
                  disabled={sending}
                  error={errors.firstName?.en?.message}
                  {...register("firstName.en")}
                />
                <TextInput
                  label="Last name"
                  placeholder="Doe"
                  required
                  disabled={sending}
                  error={errors.lastName?.en?.message}
                  {...register("lastName.en")}
                />
              </SimpleGrid>

              <TextInput
                label="Email"
                type="email"
                placeholder="john@example.com"
                required
                disabled={sending}
                error={errors.email?.message}
                {...register("email")}
              />

              <ControlledPhoneField
                control={control}
                name="phone"
                label="Phone"
                required
                disabled={sending}
              />

              <div>
                <PasswordInput
                  label="Password"
                  placeholder="Create a strong password"
                  required
                  disabled={sending}
                  error={errors.password?.message}
                  {...register("password")}
                />
                <PasswordChecklist value={passwordValue} />
              </div>

              <PasswordInput
                label="Confirm password"
                placeholder="Re-enter your password"
                required
                disabled={sending}
                error={errors.confirmPassword?.message}
                {...register("confirmPassword")}
              />

              {error ? (
                <Alert
                  color="red"
                  variant="light"
                  icon={<AlertCircle size={18} />}
                >
                  {error}
                </Alert>
              ) : null}

              <Button
                type="submit"
                color="edr-green"
                fullWidth
                loading={sending}
                rightSection={!sending ? <ArrowRight size={16} /> : undefined}
              >
                Continue
              </Button>

              <p className="text-center text-sm text-gray-500">
                Already have an account ?{" "}
                <button
                  type="button"
                  onClick={() => navigate("/login")}
                  className="font-semibold text-primary hover:underline"
                >
                  Sign In
                </button>
              </p>
            </Stack>
          </form>
        ) : (
          <OtpChannelStep
            email={pendingData?.email}
            phone={pendingData?.phone}
            value={otpCode}
            onChange={setOtpCode}
            onVerify={confirmOtp}
            onBack={() => {
              setStage("form");
              setOtpError(null);
            }}
            onResend={resendOtp}
            resendIn={resendCooldown.secondsLeft}
            sending={sending}
            verifying={verifying}
            error={otpError}
            description="Enter it to finish creating your account."
            submitLabel="Verify & create account"
          />
        )}
      </div>
    </AuthShell>
  );
}
