import { type FormEvent, useState } from "react";
import { Alert, Button, PasswordInput, Stack, TextInput } from "@mantine/core";
import { AlertCircle, ArrowLeft, ArrowRight, KeyRound } from "lucide-react";
import { Link, useNavigate } from "react-router-dom";

import {
  requestPasswordResetRequest,
  resetPasswordRequest,
  verifyPasswordResetOtpRequest,
} from "@/auth/api";
import type { ResetTicket } from "@/auth/types";
import AuthShell from "@/components/auth/AuthShell";
import OtpChannelStep, { OTP_LENGTH } from "@/components/auth/OtpChannelStep";
import PasswordChecklist from "@/components/auth/PasswordChecklist";
import { useResendCooldown } from "@/hooks/useResendCooldown";
import { normaliseIdentifier } from "@/utils/identifier";
import { meetsAllRequirements } from "@/utils/passwordSchema";
import { extractApiError } from "@/utils/result";

type Stage = "identify" | "otp" | "password";

const ForgotPasswordPage = () => {
  const navigate = useNavigate();

  const [stage, setStage] = useState<Stage>("identify");
  const [identifier, setIdentifier] = useState("");
  const [otpCode, setOtpCode] = useState("");
  // The reset ticket lives in memory only — persisting it would leave a
  // password-change credential sitting in localStorage.
  const [ticket, setTicket] = useState<ResetTicket | null>(null);
  const [password, setPassword] = useState("");
  const [confirmPassword, setConfirmPassword] = useState("");

  const [sending, setSending] = useState(false);
  const [verifying, setVerifying] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const resendCooldown = useResendCooldown();

  /** The identifier as the API will see it — normalised once, reused everywhere. */
  const normalised = normaliseIdentifier(identifier);

  const sendCode = async () => {
    await requestPasswordResetRequest({ identifier: normalised });
    setOtpCode("");
    resendCooldown.start();
  };

  // Stage 1 — ask for a code. The API answers identically for unknown accounts,
  // so we always advance; a non-existent identifier simply never receives a code.
  const handleIdentify = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setError(null);
    setSending(true);
    try {
      await sendCode();
      setStage("otp");
    } catch (err) {
      setError(extractApiError(err).message);
    } finally {
      setSending(false);
    }
  };

  const handleResend = async () => {
    setError(null);
    setSending(true);
    try {
      await sendCode();
    } catch (err) {
      setError(extractApiError(err).message);
    } finally {
      setSending(false);
    }
  };

  // Stage 2 — trade the code for a single-use ticket.
  const handleVerify = async () => {
    setError(null);
    if (otpCode.trim().length !== OTP_LENGTH) {
      setError(`Enter the ${OTP_LENGTH}-digit code we sent you.`);
      return;
    }
    setVerifying(true);
    try {
      const result = await verifyPasswordResetOtpRequest({
        identifier: normalised,
        otp: otpCode.trim(),
      });
      setTicket(result);
      setStage("password");
    } catch (err) {
      setError(extractApiError(err).message);
    } finally {
      setVerifying(false);
    }
  };

  // Stage 3 — spend the ticket on IAM's set-password.
  const handleReset = async (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    setError(null);

    if (!ticket) {
      setError("Your reset session expired. Start again.");
      setStage("identify");
      return;
    }
    if (password !== confirmPassword) {
      setError("Passwords do not match.");
      return;
    }

    setVerifying(true);
    try {
      await resetPasswordRequest({
        userId: ticket.userId,
        // The API matches this against email / username / phone, so the typed
        // identifier works regardless of which one it is.
        email: normalised,
        verificationCode: ticket.verificationCode,
        newPassword: password,
        confirmPassword,
      });
      navigate("/auth", {
        replace: true,
        state: { passwordReset: true },
      });
    } catch (err) {
      setError(extractApiError(err).message);
    } finally {
      setVerifying(false);
    }
  };

  return (
    <AuthShell
      tagline="Recover your account"
      taglineBody="Reset your EDR Freight backoffice password with a one-time code sent to your email and phone."
    >
      <div className="flex w-full flex-col">
        {stage === "identify" ? (
          <form onSubmit={handleIdentify} className="flex w-full flex-col">
            <div className="mb-1 flex justify-center">
              <span className="flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">
                <KeyRound size={22} />
              </span>
            </div>

            <div className="mb-4 mt-3 space-y-1.5 text-center sm:mb-5">
              <h1 className="text-xl font-bold tracking-tight text-gray-900 sm:text-2xl">
                Forgot your password?
              </h1>
              <p className="text-sm leading-relaxed text-gray-500">
                Enter your email or phone number and we&apos;ll send you a code to
                reset it.
              </p>
            </div>

            <Stack gap="md">
              <TextInput
                label="Email or Phone"
                placeholder="name@company.com or 09XXXXXXXX"
                autoComplete="username"
                required
                disabled={sending}
                value={identifier}
                onChange={(event) => setIdentifier(event.target.value)}
              />

              <p className="text-xs text-gray-500">
                The code goes to the email and phone on your account, which may
                differ from what you typed above.
              </p>

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

              <Button
                type="submit"
                color="edr-green"
                fullWidth
                loading={sending}
                disabled={!identifier.trim()}
                rightSection={!sending ? <ArrowRight size={16} /> : undefined}
              >
                Send code
              </Button>

              <p className="text-center text-sm text-gray-500">
                Remembered it?{" "}
                <Link to="/auth" className="font-semibold text-primary hover:underline">
                  Back to sign in
                </Link>
              </p>
            </Stack>
          </form>
        ) : null}

        {stage === "otp" ? (
          <OtpChannelStep
            value={otpCode}
            onChange={setOtpCode}
            onVerify={handleVerify}
            onBack={() => {
              setStage("identify");
              setError(null);
            }}
            onResend={handleResend}
            resendIn={resendCooldown.secondsLeft}
            sending={sending}
            verifying={verifying}
            error={error}
            title="Enter your reset code"
            description="Enter it to choose a new password."
            submitLabel="Verify code"
          />
        ) : null}

        {stage === "password" ? (
          <form onSubmit={handleReset} 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">
                Choose a new password
              </h1>
              <p className="text-sm leading-relaxed text-gray-500">
                Pick something strong you haven&apos;t used before.
              </p>
            </div>

            <Stack gap="md">
              <div>
                <PasswordInput
                  label="New password"
                  placeholder="Create a strong password"
                  required
                  disabled={verifying}
                  value={password}
                  onChange={(event) => setPassword(event.target.value)}
                />
                <PasswordChecklist value={password} />
              </div>

              <PasswordInput
                label="Confirm new password"
                placeholder="Re-enter your password"
                required
                disabled={verifying}
                error={
                  confirmPassword && confirmPassword !== password
                    ? "Passwords do not match"
                    : undefined
                }
                value={confirmPassword}
                onChange={(event) => setConfirmPassword(event.target.value)}
              />

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

              <Button
                type="submit"
                color="edr-green"
                fullWidth
                loading={verifying}
                disabled={
                  verifying ||
                  !meetsAllRequirements(password) ||
                  password !== confirmPassword
                }
              >
                Reset password
              </Button>

              <Button
                variant="subtle"
                color="gray"
                leftSection={<ArrowLeft size={14} />}
                disabled={verifying}
                onClick={() => {
                  setStage("otp");
                  setError(null);
                }}
              >
                Back
              </Button>
            </Stack>
          </form>
        ) : null}
      </div>
    </AuthShell>
  );
};

export default ForgotPasswordPage;
