"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { AuthTransitionLink } from "@/components/auth-transition";
import { DismissibleBottomToast } from "@/components/dismissible-bottom-toast";
import { useI18n } from "@/components/i18n-provider";
import { StaticUiLocalizer } from "@/components/static-ui-localizer";
import {
  translateStaticUiText,
  type TranslationKey,
} from "@/lib/i18n-dictionaries";
import {
  getInvalidDomainInputMessage,
  getWwwDomainInputMessage,
  hasWwwDomainPrefix,
  isValidDomainInput,
} from "@/lib/domain-input";
import { getLocalizedPublicPath } from "@/lib/i18n-urls";
import { trackMarketingFunnelEvent } from "@/lib/marketing-funnel-client";

type SignupStepId = "account" | "domain" | "mailbox" | "dkim" | "welcome";

type SignupProgressStatus = "idle" | "running" | "complete" | "error";

type SignupStepState = {
  description: string;
  id: SignupStepId;
  status: SignupProgressStatus;
  title: string;
};

type SignupProgressChunk =
  | {
      description: string;
      status: "running" | "complete";
      step: SignupStepId;
      title: string;
      type: "progress";
    }
  | {
      redirectUrl: string;
      type: "complete";
    }
  | {
      error: string;
      message: string;
      redirectUrl?: string;
      type: "error";
    };

type SignupRecoverySendResponse = {
  challengeId: number;
  error?: string;
  expiresAt?: string;
  message?: string;
  resendAvailableAt?: string;
  secondsRemaining?: number;
};

type SignupRecoveryVerifyResponse = {
  challengeId: number;
  error?: string;
  expiresAt?: string;
  message?: string;
  verificationToken?: string;
};

type UiTranslator = (
  key: TranslationKey,
  values?: Record<string, string | number>,
) => string;

const DEFAULT_STEPS: SignupStepState[] = [
  {
    id: "account",
    title: "대표 계정 생성",
    description: "가입 정보와 기본 메일함 구조를 먼저 저장합니다.",
    status: "idle",
  },
  {
    id: "domain",
    title: "도메인 등록",
    description: "메일 서버에 도메인을 연결할 준비를 진행합니다.",
    status: "idle",
  },
  {
    id: "mailbox",
    title: "대표 메일 생성",
    description: "대표 메일 계정과 로그인 인증값을 준비합니다.",
    status: "idle",
  },
  {
    id: "dkim",
    title: "DNS 보안값 준비",
    description: "MX, SPF, DKIM, DMARC 연결값을 완성합니다.",
    status: "idle",
  },
  {
    id: "welcome",
    title: "초기 메일함 정리",
    description: "환영 메일과 첫 받은메일함 동기화를 마무리합니다.",
    status: "idle",
  },
];

function mapSignupErrorMessage(error: string, fallback: string, t: UiTranslator) {
  if (error === "required") {
    return t("signup.error.required");
  }

  if (error === "company-name-too-long") {
    return t("signup.error.businessNameLong");
  }

  if (error === "domain-too-long") {
    return t("signup.error.domainLong");
  }

  if (error === "password-mismatch") {
    return t("signup.error.passwordMismatch");
  }

  if (error === "terms-required") {
    return t("signup.error.termsRequired");
  }

  if (error === "recovery-email-required") {
    return t("signup.error.recoveryRequired");
  }

  if (error === "recovery-email-invalid") {
    return t("signup.error.recoveryInvalid");
  }

  if (error === "recovery-email-unverified") {
    return t("signup.error.recoveryUnverified");
  }

  if (error === "recovery-email-expired") {
    return t("signup.error.recoveryExpired");
  }

  if (error === "email-exists") {
    return t("signup.error.emailExists");
  }

  if (error === "domain-taken") {
    return t("signup.error.domainTaken");
  }

  if (error === "domain-recovery-owner-mismatch") {
    return t("signup.error.domainOwnerMismatch");
  }

  if (error === "domain-recovery-verification-required") {
    return t("signup.error.domainRecoveryVerification");
  }

  if (error === "domain-www-prefix") {
    return t("signup.error.domainWww");
  }

  if (error === "invalid-domain") {
    return t("signup.error.domainInvalid");
  }

  if (error === "invalid-local-part") {
    return t("signup.error.localPart");
  }

  if (error === "mail-config") {
    return t("signup.error.mailConfig");
  }

  if (error === "mail-auth") {
    return t("signup.error.mailAuth");
  }

  if (error === "mail-domain-exists") {
    return t("signup.error.mailDomainExists");
  }

  if (error === "mail-setup") {
    return t("signup.error.mailSetup");
  }

  return fallback || t("signup.error.default");
}

function normalizeEmail(value: string) {
  return value.trim().toLowerCase();
}

function formatCountdown(totalSeconds: number) {
  const minutes = Math.floor(totalSeconds / 60);
  const seconds = totalSeconds % 60;

  return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
}

function StatusIcon({ status }: { status: SignupProgressStatus }) {
  if (status === "complete") {
    return (
      <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#2f6df6] text-white shadow-[0_12px_28px_rgba(47,109,246,0.24)]">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2.2"
          strokeLinecap="round"
          strokeLinejoin="round"
          className="h-[17px] w-[17px]"
        >
          <path d="m5 12 4.2 4.2L19 6.7" />
        </svg>
      </span>
    );
  }

  if (status === "running") {
    return (
      <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full border border-[#cfe0ff] bg-[#f4f8ff]">
        <span
          aria-hidden="true"
          className="h-[18px] w-[18px] animate-spin rounded-full border-2 border-[#c8d9fb] border-r-[#2f6df6] border-t-[#2f6df6]"
        />
      </span>
    );
  }

  if (status === "error") {
    return (
      <span className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#fff1f3] text-[#df3866] shadow-[0_10px_24px_rgba(223,56,102,0.14)]">
        <svg
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
          className="h-[16px] w-[16px]"
        >
          <path d="m7 7 10 10" />
          <path d="m17 7-10 10" />
        </svg>
      </span>
    );
  }

  return (
    <span className="h-9 w-9 shrink-0 rounded-full border border-[#dbe4f3] bg-white" />
  );
}

function SignupProgressOverlay({
  activeMailbox,
  open,
  steps,
}: {
  activeMailbox: string;
  open: boolean;
  steps: SignupStepState[];
}) {
  const { t } = useI18n();
  if (!open) {
    return null;
  }

  const activeStep =
    steps.find((step) => step.status === "running") ??
    steps.find((step) => step.status === "error") ??
    steps.findLast((step) => step.status === "complete") ??
    steps[0];

  return (
    <StaticUiLocalizer>
    <div className="fixed inset-0 z-[160] flex items-center justify-center bg-[rgba(6,10,18,0.52)] px-4 py-6 backdrop-blur-[18px]">
      <div className="w-full max-w-[580px] overflow-hidden rounded-[30px] border border-white/35 bg-[linear-gradient(180deg,rgba(255,255,255,0.97),rgba(246,249,255,0.94))] shadow-[0_34px_90px_rgba(7,16,34,0.28)]">
        <div className="border-b border-[#e7eefb] px-7 pb-6 pt-7 sm:px-8">
          <span className="om-badge om-badge-sm om-badge-info">
            회원가입 진행 중
          </span>
          <h2 className="mt-4 text-[23px] font-semibold tracking-[-0.05em] text-[#16233c] sm:text-[26px]">
            페이지를 닫지 마세요
          </h2>
          <p className="mt-3 text-[13px] leading-6 text-[#6f7f98] sm:text-[14px]">
            {activeMailbox
              ? `${activeMailbox} 대표 메일을 준비하는 동안 단계별로 완료 상태를 표시합니다.`
              : t("signup.progress.preparing")}
          </p>
        </div>

        <div className="px-7 py-6 sm:px-8">
          <div className="rounded-[24px] border border-[#e7eefb] bg-white/90 px-5 py-5">
            <p className="text-[13px] font-semibold text-[#2f6df6]">
              현재 단계
            </p>
            <p className="mt-2 text-[18px] font-semibold tracking-[-0.04em] text-[#16233c] sm:text-[20px]">
              {activeStep?.title}
            </p>
            <p className="mt-2 text-[13px] leading-6 text-[#71819a]">
              {activeStep?.description}
            </p>
          </div>

          <div className="mt-5 space-y-3">
            {steps.map((step) => (
              <div
                key={step.id}
                className={`flex items-start gap-4 rounded-[22px] border px-4 py-4 transition-colors ${
                  step.status === "running"
                    ? "border-[#d6e3ff] bg-[#f7faff]"
                    : step.status === "complete"
                      ? "border-[#e3ebfb] bg-white"
                      : step.status === "error"
                        ? "border-[#ffd9e2] bg-[#fff8fa]"
                        : "border-[#eef2f9] bg-[#fbfcff]"
                }`}
              >
                <StatusIcon status={step.status} />
                <div className="min-w-0">
                  <p className="text-[14px] font-semibold tracking-[-0.03em] text-[#16233c] sm:text-[15px]">
                    {step.title}
                  </p>
                  <p className="mt-1 text-[12px] leading-5 text-[#70819d] sm:text-[13px] sm:leading-6">
                    {step.description}
                  </p>
                </div>
              </div>
            ))}
          </div>

          <p className="mt-5 text-center text-[11px] leading-5 text-[#7f8da5] sm:text-[12px]">
            가입이 끝나면 자동으로 메일 워크스페이스로 이동합니다.
          </p>
        </div>
      </div>
    </div>
    </StaticUiLocalizer>
  );
}

async function readSignupStream(
  response: Response,
  onChunk: (chunk: SignupProgressChunk) => Promise<void> | void,
) {
  if (!response.body) {
    throw new Error("stream-missing");
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();

    if (done) {
      break;
    }

    buffer += decoder.decode(value, { stream: true });
    let lineBreakIndex = buffer.indexOf("\n");

    while (lineBreakIndex >= 0) {
      const rawLine = buffer.slice(0, lineBreakIndex).trim();
      buffer = buffer.slice(lineBreakIndex + 1);

      if (rawLine) {
        await onChunk(JSON.parse(rawLine) as SignupProgressChunk);
      }

      lineBreakIndex = buffer.indexOf("\n");
    }
  }

  const tail = buffer.trim();

  if (tail) {
    await onChunk(JSON.parse(tail) as SignupProgressChunk);
  }
}

export function SignupPageForm({
  initialErrorMessage,
}: {
  initialErrorMessage: string | null;
}) {
  const { locale, t } = useI18n();
  const abortControllerRef = useRef<AbortController | null>(null);
  const [notice, setNotice] = useState<{
    message: string;
    tone: "error" | "success";
  } | null>(
    initialErrorMessage
      ? { tone: "error", message: translateStaticUiText(locale, initialErrorMessage) }
      : null,
  );
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [overlayOpen, setOverlayOpen] = useState(false);
  const [activeMailbox, setActiveMailbox] = useState("");
  const [steps, setSteps] = useState<SignupStepState[]>(DEFAULT_STEPS);
  const [recoveryEmail, setRecoveryEmail] = useState("");
  const [showRecoveryCodeInput, setShowRecoveryCodeInput] = useState(false);
  const [recoveryCode, setRecoveryCode] = useState("");
  const [recoveryChallengeId, setRecoveryChallengeId] = useState<number | null>(
    null,
  );
  const [recoveryVerificationToken, setRecoveryVerificationToken] =
    useState("");
  const [recoveryExpiresAtMs, setRecoveryExpiresAtMs] = useState<number | null>(
    null,
  );
  const [recoveryResendAvailableAtMs, setRecoveryResendAvailableAtMs] =
    useState<number | null>(null);
  const [isSendingRecoveryCode, setIsSendingRecoveryCode] = useState(false);
  const [isVerifyingRecoveryCode, setIsVerifyingRecoveryCode] = useState(false);
  const [nowMs, setNowMs] = useState(() => Date.now());
  const [domainPreview, setDomainPreview] = useState("");
  const [domainHelpOpen, setDomainHelpOpen] = useState(false);
  const [domainTouched, setDomainTouched] = useState(false);
  const [localPartPreview, setLocalPartPreview] = useState("");
  const [termsAccepted, setTermsAccepted] = useState(false);

  const normalizedDomainPreview = useMemo(() => {
    const normalized = domainPreview
      .trim()
      .toLowerCase()
      .replace(/^https?:\/\//, "")
      .replace(/[/?#].*$/, "")
      .replace(/:\d+$/, "")
      .replace(/^www\./, "")
      .replace(/[^a-z0-9.-]/g, "")
      .replace(/^\.+|\.+$/g, "");

    return normalized || "yourdomain.com";
  }, [domainPreview]);

  const domainErrorMessage = useMemo(() => {
    if (!domainPreview.trim()) {
      return "";
    }

    if (hasWwwDomainPrefix(domainPreview)) {
      return getWwwDomainInputMessage(domainPreview);
    }

    return isValidDomainInput(domainPreview)
      ? ""
      : getInvalidDomainInputMessage();
  }, [domainPreview]);

  useEffect(() => {
    void trackMarketingFunnelEvent("signup_form_viewed");

    return () => {
      abortControllerRef.current?.abort();
    };
  }, []);

  useEffect(() => {
    if (
      !showRecoveryCodeInput &&
      !recoveryExpiresAtMs &&
      !recoveryResendAvailableAtMs
    ) {
      return;
    }

    const timer = window.setInterval(() => {
      setNowMs(Date.now());
    }, 1000);

    return () => window.clearInterval(timer);
  }, [recoveryExpiresAtMs, recoveryResendAvailableAtMs, showRecoveryCodeInput]);

  const recoverySecondsRemaining = recoveryExpiresAtMs
    ? Math.max(0, Math.ceil((recoveryExpiresAtMs - nowMs) / 1000))
    : 0;
  const resendSecondsRemaining = recoveryResendAvailableAtMs
    ? Math.max(0, Math.ceil((recoveryResendAvailableAtMs - nowMs) / 1000))
    : 0;
  const isRecoveryVerified = Boolean(
    recoveryChallengeId &&
    recoveryVerificationToken &&
    recoverySecondsRemaining > 0,
  );
  const isRecoveryExpired =
    showRecoveryCodeInput &&
    recoveryExpiresAtMs !== null &&
    recoverySecondsRemaining <= 0;
  const canSubmit = useMemo(
    () => !isSubmitting && isRecoveryVerified && termsAccepted,
    [isRecoveryVerified, isSubmitting, termsAccepted],
  );

  const resetSteps = () => {
    setSteps(DEFAULT_STEPS);
  };

  const resetRecoveryVerification = () => {
    setShowRecoveryCodeInput(false);
    setRecoveryCode("");
    setRecoveryChallengeId(null);
    setRecoveryVerificationToken("");
    setRecoveryExpiresAtMs(null);
    setRecoveryResendAvailableAtMs(null);
  };

  const updateStep = (
    stepId: SignupStepId,
    status: SignupProgressStatus,
    title?: string,
    description?: string,
  ) => {
    setSteps((current) =>
      current.map((step) => {
        if (step.id !== stepId) {
          return status === "running" && step.status === "running"
            ? { ...step, status: "complete" }
            : step;
        }

        return {
          ...step,
          status,
          title: title ?? step.title,
          description: description ?? step.description,
        };
      }),
    );
  };

  const markUntil = (stepId: SignupStepId) => {
    setSteps((current) => {
      let shouldComplete = true;

      return current.map((step) => {
        if (step.id === stepId) {
          shouldComplete = false;
          return step;
        }

        if (shouldComplete && step.status !== "complete") {
          return { ...step, status: "complete" };
        }

        return step;
      });
    });
  };

  const handleRecoveryEmailChange = (
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    const nextValue = event.target.value;

    if (normalizeEmail(nextValue) !== normalizeEmail(recoveryEmail)) {
      resetRecoveryVerification();
    }

    setRecoveryEmail(nextValue);
  };

  const handleSendRecoveryCode = async () => {
    const normalizedRecoveryEmail = normalizeEmail(recoveryEmail);

    if (!normalizedRecoveryEmail) {
      setNotice({
        tone: "error",
        message: t("signup.error.recoveryRequired"),
      });
      return;
    }

    if (resendSecondsRemaining > 0) {
      setNotice({
        tone: "error",
        message: t("signup.message.resendWait", { seconds: resendSecondsRemaining }),
      });
      return;
    }

    setShowRecoveryCodeInput(true);
    setIsSendingRecoveryCode(true);
    setRecoveryVerificationToken("");
    setNotice(null);

    try {
      const response = await fetch("/api/auth/signup-recovery/send", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          challengeId: recoveryChallengeId,
          recoveryEmail: normalizedRecoveryEmail,
        }),
      });
      const payload = (await response
        .json()
        .catch(() => null)) as SignupRecoverySendResponse | null;

      if (
        !response.ok ||
        !payload?.challengeId ||
        !payload.expiresAt ||
        !payload.resendAvailableAt
      ) {
        throw new Error(
          locale === "ko" ? payload?.message ?? t("signup.error.codeSend") : t("signup.error.codeSend"),
        );
      }

      setRecoveryChallengeId(payload.challengeId);
      setRecoveryVerificationToken("");
      setRecoveryCode("");
      setRecoveryExpiresAtMs(Date.parse(payload.expiresAt));
      setRecoveryResendAvailableAtMs(Date.parse(payload.resendAvailableAt));
      setNotice({
        tone: "success",
        message: recoveryChallengeId
          ? t("signup.message.codeResent")
          : t("signup.message.codeSent"),
      });
      void trackMarketingFunnelEvent("signup_recovery_sent");
    } catch (error) {
      setNotice({
        tone: "error",
        message:
          error instanceof Error
            ? error.message
            : t("signup.error.codeSend"),
      });
    } finally {
      setIsSendingRecoveryCode(false);
    }
  };

  const handleVerifyRecoveryCode = async () => {
    const normalizedRecoveryEmail = normalizeEmail(recoveryEmail);

    if (!recoveryChallengeId) {
      setNotice({
        tone: "error",
        message: t("signup.error.codeRequestFirst"),
      });
      return;
    }

    if (isRecoveryExpired) {
      setNotice({
        tone: "error",
        message: t("signup.error.recoveryExpired"),
      });
      return;
    }

    if (!recoveryCode.trim()) {
      setNotice({
        tone: "error",
        message: t("signup.error.codeRequired"),
      });
      return;
    }

    setIsVerifyingRecoveryCode(true);
    setNotice(null);

    try {
      const response = await fetch("/api/auth/signup-recovery/verify", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          challengeId: recoveryChallengeId,
          code: recoveryCode.trim(),
          recoveryEmail: normalizedRecoveryEmail,
        }),
      });
      const payload = (await response
        .json()
        .catch(() => null)) as SignupRecoveryVerifyResponse | null;

      if (!response.ok || !payload?.verificationToken || !payload?.expiresAt) {
        if (payload?.error === "expired") {
          setRecoveryExpiresAtMs(Date.now());
        }

        throw new Error(
          locale === "ko" ? payload?.message ?? t("signup.error.codeVerify") : t("signup.error.codeVerify"),
        );
      }

      setRecoveryVerificationToken(payload.verificationToken);
      setRecoveryChallengeId(payload.challengeId);
      setRecoveryExpiresAtMs(Date.parse(payload.expiresAt));
      setNotice({
        tone: "success",
        message: t("signup.message.verified"),
      });
      void trackMarketingFunnelEvent("signup_recovery_verified");
    } catch (error) {
      setRecoveryVerificationToken("");
      setNotice({
        tone: "error",
        message:
          error instanceof Error
            ? error.message
            : t("signup.error.codeVerify"),
      });
    } finally {
      setIsVerifyingRecoveryCode(false);
    }
  };

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    if (!canSubmit) {
      setNotice({
        tone: "error",
        message: !isRecoveryVerified
          ? isRecoveryExpired
            ? t("signup.error.recoveryExpired")
            : t("signup.error.recoveryUnverified")
          : t("signup.error.termsRequired"),
      });
      return;
    }

    const formData = new FormData(event.currentTarget);
    const companyName = String(formData.get("companyName") ?? "").trim();
    const domain = String(formData.get("domain") ?? "")
      .trim()
      .toLowerCase();
    const localPart = String(formData.get("localPart") ?? "")
      .trim()
      .toLowerCase();
    const password = String(formData.get("password") ?? "");
    const passwordConfirm = String(formData.get("passwordConfirm") ?? "");
    const normalizedRecoveryEmail = normalizeEmail(recoveryEmail);
    const mailbox = domain && localPart ? `${localPart}@${domain}` : "";

    if (hasWwwDomainPrefix(domain)) {
      setNotice({
        tone: "error",
        message: getWwwDomainInputMessage(domain),
      });
      return;
    }

    if (!isValidDomainInput(domain)) {
      setDomainTouched(true);
      setNotice({
        tone: "error",
        message: getInvalidDomainInputMessage(),
      });
      return;
    }

    if (!normalizedRecoveryEmail) {
      setNotice({
        tone: "error",
        message: t("signup.error.recoveryRequired"),
      });
      return;
    }

    abortControllerRef.current?.abort();
    abortControllerRef.current = new AbortController();
    setNotice(null);
    resetSteps();
    updateStep(
      "account",
      "running",
      t("signup.progress.accountRunning"),
      t("signup.progress.accountRunningDescription"),
    );
    setActiveMailbox(mailbox);
    setOverlayOpen(true);
    setIsSubmitting(true);
    void trackMarketingFunnelEvent("signup_submitted");
    let failureDetail = "unknown";

    try {
      const response = await fetch("/api/auth/signup", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          companyName,
          domain,
          localPart,
          password,
          passwordConfirm,
          recoveryEmail: normalizedRecoveryEmail,
          recoveryVerificationId: recoveryChallengeId,
          recoveryVerificationToken,
          termsAccepted,
        }),
        credentials: "include",
        signal: abortControllerRef.current.signal,
      });

      if (!response.ok) {
        const payload = (await response.json().catch(() => null)) as {
          error?: string;
          message?: string;
        } | null;
        failureDetail = payload?.error ?? "system";
        throw new Error(
          mapSignupErrorMessage(
            payload?.error ?? "system",
            payload?.message ?? "",
            t,
          ),
        );
      }

      await readSignupStream(response, async (chunk) => {
        if (chunk.type === "progress") {
          if (chunk.status === "running") {
            markUntil(chunk.step);
          }

          updateStep(chunk.step, chunk.status, chunk.title, chunk.description);
          return;
        }

        if (chunk.type === "error") {
          failureDetail = chunk.error || "stream_error";
          const message = mapSignupErrorMessage(chunk.error, chunk.message, t);
          setSteps((current) => {
            const activeStepId =
              [...current].findLast((step) => step.status === "running")?.id ??
              "welcome";

            return current.map((step) =>
              step.id === activeStepId
                ? {
                    ...step,
                    status: "error",
                    title: "가입 마무리 실패",
                    description: message,
                  }
                : step,
            );
          });

          if (chunk.redirectUrl) {
            const redirectUrl = chunk.redirectUrl;
            window.setTimeout(() => {
              window.location.assign(redirectUrl);
            }, 900);
            return;
          }

          throw new Error(message);
        }

        if (chunk.type === "complete") {
          setSteps((current) =>
            current.map((step) => ({
              ...step,
              status: "complete",
            })),
          );

          window.setTimeout(() => {
            window.location.assign(chunk.redirectUrl);
          }, 420);
        }
      });
    } catch (error) {
      if (error instanceof DOMException && error.name === "AbortError") {
        return;
      }

      void trackMarketingFunnelEvent("signup_failed", failureDetail);
      setOverlayOpen(false);
      resetSteps();
      setNotice({
        tone: "error",
        message:
          error instanceof Error
            ? error.message
            : t("signup.error.default"),
      });
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <StaticUiLocalizer>
    <>
      <DismissibleBottomToast
        notice={notice}
        clearSearchParams={["error", "success", "details"]}
      />

      <form onSubmit={handleSubmit} className="space-y-3.5">
        <label className="block">
          <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
            사업자명
          </span>
          <input
            required
            type="text"
            name="companyName"
            maxLength={191}
            className="h-12 w-full rounded-[14px] border border-[#d7deea] bg-white px-4 text-[14px] text-[#101418] outline-none transition-colors focus:border-[#bcd1ff] focus:bg-white"
            placeholder="사업자명을 입력하세요"
          />
        </label>

        <div className="grid grid-cols-1 gap-3.5">
          <div className="block">
            <div className="mb-1.5 flex items-center gap-1.5 text-[13px] font-medium text-[#6f7784]">
              <label htmlFor="signup-domain">연결할 도메인</label>
              <span className="relative inline-flex">
                <button
                  type="button"
                  aria-expanded={domainHelpOpen}
                  aria-label="연결할 도메인 도움말"
                  aria-describedby={domainHelpOpen ? "signup-domain-help" : undefined}
                  onClick={() => setDomainHelpOpen((current) => !current)}
                  onBlur={() => setDomainHelpOpen(false)}
                  className="inline-flex h-[17px] w-[17px] cursor-pointer items-center justify-center rounded-full border border-[#c9d5e8] bg-white text-[11px] font-semibold leading-none text-[#70819d] transition-colors hover:border-[#9ebcff] hover:text-[#2f6df6] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#d7e5ff]"
                >
                  ?
                </button>
                {domainHelpOpen ? (
                  <span
                    id="signup-domain-help"
                    role="tooltip"
                    className="absolute bottom-[calc(100%+8px)] left-0 z-20 w-[250px] max-w-[calc(100vw-32px)] rounded-[12px] border border-[#dfe8f8] bg-white px-3.5 py-3 text-[12px] font-medium leading-5 text-[#40516f] shadow-[0_18px_44px_rgba(18,32,65,0.14)]"
                  >
                    대표님이 구매하신 도메인을 입력해주세요!
                  </span>
                ) : null}
              </span>
            </div>
            <input
              id="signup-domain"
              required
              type="text"
              name="domain"
              maxLength={253}
              aria-invalid={domainTouched && Boolean(domainErrorMessage)}
              aria-describedby={
                domainTouched && domainErrorMessage
                  ? "signup-domain-error"
                  : undefined
              }
              className={`h-12 w-full rounded-[14px] border bg-white px-4 text-[14px] text-[#101418] outline-none transition-colors focus:bg-white ${
                domainTouched && domainErrorMessage
                  ? "border-[#e8a5ad] focus:border-[#d86b78]"
                  : "border-[#d7deea] focus:border-[#bcd1ff]"
              }`}
              placeholder="예: 내도메인.com"
              onChange={(event) => {
                setDomainPreview(event.currentTarget.value);
              }}
              onBlur={(event) => {
                setDomainTouched(true);
                const value = event.currentTarget.value;

                if (!value.trim()) {
                  return;
                }

                const message = hasWwwDomainPrefix(value)
                  ? getWwwDomainInputMessage(value)
                  : isValidDomainInput(value)
                    ? ""
                    : getInvalidDomainInputMessage();

                if (message) {
                  setNotice({ tone: "error", message });
                }
              }}
            />
            {domainTouched && domainErrorMessage ? (
              <span
                id="signup-domain-error"
                className="mt-1.5 block text-[12px] leading-5 text-[#c04b59]"
              >
                {domainErrorMessage}
              </span>
            ) : null}
          </div>

          <label className="block">
            <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
              대표 메일 주소
            </span>
            <div className="flex h-12 w-full min-w-0 items-center overflow-hidden rounded-[14px] border border-[#d7deea] bg-white transition-colors focus-within:border-[#bcd1ff]">
              <input
                required
                type="text"
                name="localPart"
                maxLength={64}
                pattern="^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$"
                className="h-full min-w-[96px] flex-1 border-0 bg-transparent px-4 text-[14px] text-[#101418] outline-none"
                placeholder="contact"
                onChange={(event) => {
                  setLocalPartPreview(event.currentTarget.value);
                }}
              />
              <span className="max-w-[58%] shrink-0 truncate border-l border-[#e7ebf2] bg-[#f8faff] px-3 text-[13px] font-medium text-[#526784]">
                @{normalizedDomainPreview}
              </span>
            </div>
            <span className="mt-1.5 block truncate text-[12px] text-[#8a94a3]">
              생성될 주소: {localPartPreview.trim() || "mail"}@
              {normalizedDomainPreview}
            </span>
          </label>
        </div>

        <label className="block">
          <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
            대표 메일 비밀번호
          </span>
          <input
            required
            type="password"
            name="password"
            minLength={6}
            autoComplete="new-password"
            className="h-12 w-full rounded-[14px] border border-[#d7deea] bg-white px-4 text-[14px] text-[#101418] outline-none transition-colors focus:border-[#bcd1ff] focus:bg-white"
            placeholder="대표 메일 로그인에 사용할 비밀번호"
          />
          <span className="mt-1.5 block text-[12px] text-[#8a94a3]">
            최소 6자 이상 입력해주세요.
          </span>
        </label>

        <label className="block">
          <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
            비밀번호 확인
          </span>
          <input
            required
            type="password"
            name="passwordConfirm"
            minLength={6}
            autoComplete="new-password"
            className="h-12 w-full rounded-[14px] border border-[#d7deea] bg-white px-4 text-[14px] text-[#101418] outline-none transition-colors focus:border-[#bcd1ff] focus:bg-white"
            placeholder="비밀번호 다시 입력"
          />
        </label>

        <div className="pt-1">
          <div className="grid gap-3 sm:grid-cols-[minmax(0,1fr)_128px] sm:items-end">
            <label className="block">
              <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
                보조 이메일
              </span>
              <input
                required
                type="email"
                name="recoveryEmail"
                value={recoveryEmail}
                maxLength={320}
                autoComplete="email"
                onChange={handleRecoveryEmailChange}
                className="h-12 w-full rounded-[14px] border border-[#d7deea] bg-white px-4 text-[14px] text-[#101418] outline-none transition-colors focus:border-[#bcd1ff] focus:bg-white"
                placeholder="비밀번호 찾기 링크를 받을 이메일"
              />
            </label>

            <button
              type="button"
              onClick={handleSendRecoveryCode}
              disabled={isSendingRecoveryCode}
              className="h-12 rounded-[14px] border border-[#d4def2] bg-white px-4 text-[13px] font-semibold text-[#24324a] transition-colors hover:border-[#b9cbed] hover:bg-[#f7faff] disabled:cursor-not-allowed disabled:opacity-60"
            >
              {isSendingRecoveryCode
                ? "전송 중..."
                : showRecoveryCodeInput
                  ? "재발송"
                  : "인증하기"}
            </button>
          </div>

          {showRecoveryCodeInput ? (
            <div className="mt-3">
              <div className="grid gap-3 sm:grid-cols-[minmax(0,1fr)_108px] sm:items-end">
                <label className="block">
                  <span className="mb-1.5 block text-[13px] font-medium text-[#6f7784]">
                    인증번호
                  </span>
                  <input
                    inputMode="numeric"
                    pattern="[0-9]*"
                    value={recoveryCode}
                    onChange={(event) =>
                      setRecoveryCode(
                        event.target.value.replace(/\D+/g, "").slice(0, 6),
                      )
                    }
                    className="h-12 w-full rounded-[14px] border border-[#d7deea] bg-white px-4 text-[14px] tracking-[0.12em] text-[#101418] outline-none transition-colors focus:border-[#bcd1ff] focus:bg-white"
                    placeholder="6자리 입력"
                  />
                </label>

                <button
                  type="button"
                  onClick={handleVerifyRecoveryCode}
                  disabled={isVerifyingRecoveryCode || isRecoveryVerified}
                  className="h-12 rounded-[14px] border border-[#2f6df6] bg-[#f4f8ff] px-4 text-[13px] font-semibold text-[#2f6df6] transition-colors hover:bg-[#edf4ff] disabled:cursor-not-allowed disabled:opacity-60"
                >
                  {isVerifyingRecoveryCode
                    ? "확인 중..."
                    : isRecoveryVerified
                      ? "인증완료"
                      : "확인"}
                </button>
              </div>

              <div className="mt-3 flex flex-wrap items-center justify-between gap-2 text-[12px]">
                <span
                  className={
                    isRecoveryExpired
                      ? "font-medium text-[#d9485c]"
                      : "text-[#64748b]"
                  }
                >
                  {isRecoveryExpired
                    ? t("signup.error.recoveryExpired")
                    : t("signup.message.timeRemaining", {
                        time: formatCountdown(recoverySecondsRemaining),
                      })}
                </span>
                <span
                  className={
                    isRecoveryVerified
                      ? "font-semibold text-[#2f6df6]"
                      : resendSecondsRemaining > 0
                        ? "text-[#7f8791]"
                        : "text-[#7f8791]"
                  }
                >
                  {isRecoveryVerified
                    ? "보조 이메일 인증 완료"
                    : resendSecondsRemaining > 0
                      ? t("signup.message.resendWaitShort", {
                          seconds: resendSecondsRemaining,
                        })
                      : t("signup.recovery.resendAvailable")}
                </span>
              </div>
            </div>
          ) : (
            <p className="mt-2 text-[12px] leading-5 text-[#8a94a3]">
              보조 이메일은 비밀번호 찾기 링크를 받을 주소이며, 인증을 완료해야
              가입할 수 있습니다.
            </p>
          )}
        </div>

        <div className="flex items-start justify-between gap-3 px-0.5 py-1">
          <label className="flex min-w-0 cursor-pointer items-start gap-2.5">
            <input
              type="checkbox"
              name="termsAccepted"
              checked={termsAccepted}
              onChange={(event) => setTermsAccepted(event.target.checked)}
              required
              className="mt-0.5 h-4 w-4 shrink-0 cursor-pointer rounded border-[#c7d2e4] accent-[#2f6df6]"
            />
            <span className="text-[12px] leading-5 text-[#53647e]">
              <span className="font-semibold text-[#2f6df6]">{t("signup.terms.required")}</span>{" "}
              {t("signup.terms.agree")}
            </span>
          </label>
          <div className="flex shrink-0 items-center gap-2 text-[11px] font-semibold text-[#2f6df6]">
            <a
              href={`https://officialsite.kr${getLocalizedPublicPath("/terms", locale)}`}
              target="_blank"
              rel="noopener noreferrer"
              className="transition-colors hover:text-[#1f5fe0] hover:underline"
            >
              {t("signup.terms.view")}
            </a>
            <span className="h-3 w-px bg-[#dce3ee]" aria-hidden="true" />
            <a
              href={`https://officialsite.kr${getLocalizedPublicPath("/privacy", locale)}`}
              target="_blank"
              rel="noopener noreferrer"
              className="transition-colors hover:text-[#1f5fe0] hover:underline"
            >
              {t("signup.privacy.view")}
            </a>
          </div>
        </div>

        <button
          type="submit"
          disabled={!canSubmit}
          className="om-btn-primary h-12 w-full rounded-[14px] px-5 text-[14px] font-semibold disabled:cursor-not-allowed"
        >
          {isSubmitting
            ? "가입 준비 중..."
            : isRecoveryVerified
              ? "무료로 시작하기"
              : "보조 이메일 인증 후 가입"}
        </button>
      </form>

      <div className="mt-5 text-center text-[13px] text-[#7f8791]">
        이미 계정이 있다면{" "}
        <AuthTransitionLink href="/login" className="font-semibold text-[#2f6df6]">
          로그인
        </AuthTransitionLink>
      </div>
      <p className="mt-4 text-center text-[12px] leading-5 text-[#9099a5]">
        가입이 완료되면 생성된 대표 메일 주소 자체가 관리자 로그인 계정이
        됩니다.
      </p>

      <SignupProgressOverlay
        open={overlayOpen}
        steps={steps}
        activeMailbox={activeMailbox}
      />
    </>
    </StaticUiLocalizer>
  );
}
