import { useState, useCallback } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Link, useNavigate } from "react-router-dom";
import { AxiosError } from "axios";
import { signup } from "@/api/auth.api";
import type { ApiError } from "@/types/api";

/* ───── 정규식 ───── */
const pwRegex =
  /^(?=.*[a-zA-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]).{8,}$/;
const nameRegex = /^[가-힣]{2,}$/;
const phoneRegex = /^\d{2,3}-\d{3,4}-\d{4}$/;

/* ───── zod 스키마 ───── */
const signupSchema = z
  .object({
    email: z
      .string()
      .min(1, "이메일을 입력해주세요.")
      .email("올바른 이메일 형식이 아닙니다."),
    password: z
      .string()
      .min(1, "비밀번호를 입력해주세요.")
      .regex(pwRegex, "8자 이상, 영문/숫자/특수문자 포함"),
    passwordConfirm: z.string().min(1, "비밀번호 확인을 입력해주세요."),
    name: z
      .string()
      .min(1, "이름을 입력해주세요.")
      .regex(nameRegex, "한글 2자 이상 입력해주세요."),
    phone: z
      .string()
      .min(1, "전화번호를 입력해주세요.")
      .regex(phoneRegex, "올바른 전화번호 형식이 아닙니다."),
    agree: z.literal(true, { message: "약관에 동의해주세요." }),
  })
  .refine((data) => data.password === data.passwordConfirm, {
    message: "비밀번호가 일치하지 않습니다.",
    path: ["passwordConfirm"],
  });

type SignupForm = z.infer<typeof signupSchema>;

export default function SignupPage() {
  const navigate = useNavigate();
  const [shakeFields, setShakeFields] = useState<Set<string>>(new Set());
  const [emailSentModal, setEmailSentModal] = useState(false);
  const [termsModal, setTermsModal] = useState(false);
  const [privacyModal, setPrivacyModal] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [serverError, setServerError] = useState<string | null>(null);

  const {
    register,
    handleSubmit,
    watch,
    setValue,
    setError,
    formState: { errors },
  } = useForm<SignupForm>({
    resolver: zodResolver(signupSchema),
    mode: "onChange",
    defaultValues: { agree: false as unknown as true },
  });

  const password = watch("password");
  const passwordConfirm = watch("passwordConfirm");

  /* 비밀번호 일치 상태 */
  const pwMatchStatus =
    !passwordConfirm
      ? null
      : passwordConfirm === password
        ? "match"
        : "mismatch";

  /* shake 트리거 */
  const triggerShake = useCallback((fieldNames: string[]) => {
    setShakeFields(new Set(fieldNames));
    setTimeout(() => setShakeFields(new Set()), 400);
  }, []);

  /* 전화번호 자동 하이픈 */
  const handlePhoneInput = (e: React.ChangeEvent<HTMLInputElement>) => {
    let v = e.target.value.replace(/[^0-9]/g, "");
    if (v.length > 3 && v.length <= 7) {
      v = v.slice(0, 3) + "-" + v.slice(3);
    } else if (v.length > 7) {
      v = v.slice(0, 3) + "-" + v.slice(3, 7) + "-" + v.slice(7, 11);
    }
    setValue("phone", v, { shouldValidate: true });
  };

  /* 가입 요청 */
  const onSubmit = async (data: SignupForm) => {
    setIsLoading(true);
    setServerError(null);
    try {
      await signup({
        email: data.email,
        password: data.password,
        name: data.name,
        phone: data.phone,
        agreeTerms: data.agree,
        agreePrivacy: data.agree,
      });
      setEmailSentModal(true);
    } catch (err) {
      const axiosErr = err as AxiosError<ApiError>;
      const code = axiosErr.response?.data?.code;
      const msg = axiosErr.response?.data?.msg;

      if (axiosErr.response?.status === 409 || code === "EMAIL_DUPLICATE") {
        setError("email", { message: msg ?? "이미 사용 중인 이메일입니다." });
        triggerShake(["email"]);
      } else {
        setServerError(msg ?? "회원가입에 실패했습니다. 다시 시도해주세요.");
      }
    } finally {
      setIsLoading(false);
    }
  };

  /* 유효성 실패 → shake */
  const onError = (fieldErrors: typeof errors) => {
    triggerShake(Object.keys(fieldErrors));
  };

  /* 힌트 스타일 헬퍼 */
  const hintClass = (field: keyof SignupForm, defaultMsg: string) => {
    const err = errors[field];
    const isError = !!err;
    return {
      className: `mt-1.5 flex items-center gap-1.5 text-xs ${isError ? "text-red-600" : "text-gray-500"}`,
      icon: isError ? "error" : "info",
      message: isError ? (err.message as string) : defaultMsg,
    };
  };

  /* 입력 필드 공통 className */
  const inputClass = (field: keyof SignupForm) =>
    `w-full rounded border bg-white px-4 py-3 font-sans text-sm text-gray-900 placeholder-gray-400 transition-all focus:border-transparent focus:outline-none focus:ring-2 focus:ring-primary ${
      errors[field]
        ? "border-red-500 shadow-[0_0_0_2px_rgba(239,68,68,0.15)]"
        : "border-gray-300"
    } ${shakeFields.has(field) ? "animate-shake" : ""}`;

  return (
    <>
      <div className="my-auto flex w-full max-w-[500px] flex-col items-center">
        {/* 로고 */}
        <div className="mb-8 text-center">
          <h1 className="mb-2 text-4xl font-black tracking-tight text-primary">
            SPMS
          </h1>
          <p className="text-sm font-medium text-gray-400">
            Stein Push Message Service
          </p>
        </div>

        {/* 카드 */}
        <div className="w-full rounded-xl bg-white p-8 shadow-2xl md:p-10">
          {/* 헤더 */}
          <div className="mb-8 flex items-center justify-between">
            <div>
              <h2 className="text-2xl font-bold text-foreground">회원가입</h2>
              <p className="mt-1 text-sm text-gray-500">
                사용자 정보를 입력해주세요.
              </p>
            </div>
            <Link
              to="/login"
              className="rounded-lg p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600"
            >
              <span className="material-symbols-outlined text-2xl">close</span>
            </Link>
          </div>

          {/* 폼 */}
          <form
            className="space-y-5"
            onSubmit={handleSubmit(onSubmit, onError)}
            noValidate
          >
            {/* 서버 에러 */}
            {serverError && (
              <div className="flex items-center gap-2 rounded-lg border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-700">
                <span
                  className="material-symbols-outlined flex-shrink-0"
                  style={{ fontSize: "14px" }}
                >
                  error
                </span>
                <span>{serverError}</span>
              </div>
            )}

            {/* 이메일 */}
            <div>
              <label className="mb-1.5 block text-sm font-bold text-gray-700">
                이메일
              </label>
              <input
                type="email"
                autoComplete="email"
                placeholder="user@spms.com"
                className={inputClass("email")}
                {...register("email")}
              />
              {(() => {
                const h = hintClass(
                  "email",
                  "인증 메일이 발송되므로 사용 가능한 이메일을 입력해주세요.",
                );
                return (
                  <div className={h.className}>
                    <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                      {h.icon}
                    </span>
                    <span>{h.message}</span>
                  </div>
                );
              })()}
            </div>

            {/* 비밀번호 */}
            <div>
              <label className="mb-1.5 block text-sm font-bold text-gray-700">
                비밀번호
              </label>
              <input
                type="password"
                placeholder="비밀번호를 입력하세요"
                className={inputClass("password")}
                {...register("password")}
              />
              {(() => {
                const h = hintClass(
                  "password",
                  "8자 이상, 영문/숫자/특수문자 포함",
                );
                return (
                  <div className={h.className}>
                    <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                      {h.icon}
                    </span>
                    <span>{h.message}</span>
                  </div>
                );
              })()}
            </div>

            {/* 비밀번호 확인 */}
            <div>
              <label className="mb-1.5 block text-sm font-bold text-gray-700">
                비밀번호 확인
              </label>
              <input
                type="password"
                placeholder="비밀번호를 다시 입력하세요"
                className={inputClass("passwordConfirm")}
                {...register("passwordConfirm")}
              />
              {pwMatchStatus === "mismatch" && (
                <div className="mt-1.5 flex items-center gap-1.5 text-xs text-red-600">
                  <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                    error
                  </span>
                  <span>비밀번호가 일치하지 않습니다.</span>
                </div>
              )}
              {pwMatchStatus === "match" && !errors.passwordConfirm && (
                <div className="mt-1.5 flex items-center gap-1.5 text-xs text-green-600">
                  <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                    check_circle
                  </span>
                  <span>비밀번호가 일치합니다.</span>
                </div>
              )}
            </div>

            {/* 구분선 */}
            <div className="my-1 border-t border-gray-200" />

            {/* 이름 */}
            <div>
              <label className="mb-1.5 block text-sm font-bold text-gray-700">
                이름
              </label>
              <input
                type="text"
                autoComplete="one-time-code"
                placeholder="홍길동"
                className={inputClass("name")}
                {...register("name")}
              />
              {errors.name && (
                <div className="mt-1.5 flex items-center gap-1.5 text-xs text-red-600">
                  <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                    error
                  </span>
                  <span>{errors.name.message}</span>
                </div>
              )}
            </div>

            {/* 전화번호 */}
            <div>
              <label className="mb-1.5 block text-sm font-bold text-gray-700">
                전화번호
              </label>
              <input
                type="tel"
                autoComplete="one-time-code"
                maxLength={13}
                placeholder="010-0000-0000"
                className={inputClass("phone")}
                {...register("phone", { onChange: handlePhoneInput })}
              />
              {errors.phone && (
                <div className="mt-1.5 flex items-center gap-1.5 text-xs text-red-600">
                  <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                    error
                  </span>
                  <span>{errors.phone.message}</span>
                </div>
              )}
            </div>

            {/* 약관 동의 */}
            <div className="pt-2">
              <label className="group flex cursor-pointer items-center gap-2.5">
                <div className="relative flex flex-shrink-0 items-center justify-center">
                  <input
                    type="checkbox"
                    className={`peer size-5 cursor-pointer appearance-none rounded border-2 transition-all checked:border-primary checked:bg-primary ${
                      errors.agree ? "border-red-500" : "border-gray-300"
                    } ${shakeFields.has("agree") ? "animate-shake" : ""}`}
                    {...register("agree")}
                  />
                  <span className="material-symbols-outlined pointer-events-none absolute text-sm text-white opacity-0 peer-checked:opacity-100">
                    check
                  </span>
                </div>
                <span
                  className={`text-sm transition-colors ${
                    errors.agree ? "text-red-500" : "text-gray-600"
                  } ${shakeFields.has("agree") ? "animate-shake" : ""}`}
                >
                  <button
                    type="button"
                    onClick={() => setTermsModal(true)}
                    className="font-semibold text-primary underline hover:text-[#1d4ed8]"
                  >
                    서비스 이용약관
                  </button>
                  {" 및 "}
                  <button
                    type="button"
                    onClick={() => setPrivacyModal(true)}
                    className="font-semibold text-primary underline hover:text-[#1d4ed8]"
                  >
                    개인정보 처리방침
                  </button>
                  에 동의합니다.
                </span>
              </label>
            </div>

            {/* 가입 버튼 */}
            <div className="pt-4">
              <button
                type="submit"
                disabled={isLoading}
                className="flex w-full items-center justify-center gap-2 rounded-lg bg-primary py-3.5 px-4 font-bold text-white shadow-lg shadow-blue-500/20 transition-all hover:bg-[#1d4ed8] active:scale-[0.98] disabled:cursor-not-allowed disabled:opacity-60"
              >
                {isLoading ? (
                  <>
                    <span className="material-symbols-outlined animate-spin text-lg">
                      progress_activity
                    </span>
                    가입 처리 중…
                  </>
                ) : (
                  "가입하기"
                )}
              </button>
            </div>
          </form>

          {/* 하단 로그인 링크 */}
          <div className="mt-8 border-t border-gray-100 pt-6 text-center">
            <p className="text-sm text-gray-500">
              이미 계정이 있으신가요?
              <Link
                to="/login"
                className="ml-1 font-semibold text-primary hover:text-[#1d4ed8] hover:underline"
              >
                로그인하기
              </Link>
            </p>
          </div>
        </div>
      </div>

      {/* ───── 인증 메일 전송 모달 ───── */}
      {emailSentModal && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4">
          <div className="w-full max-w-md rounded-xl bg-white p-6 shadow-2xl">
            <div className="mb-4 flex items-center gap-3">
              <div className="flex size-10 flex-shrink-0 items-center justify-center rounded-full bg-green-100">
                <span className="material-symbols-outlined text-xl text-green-600">
                  mark_email_read
                </span>
              </div>
              <h3 className="text-lg font-bold text-foreground">
                인증 메일을 전송했습니다
              </h3>
            </div>
            <p className="mb-2 text-sm text-foreground">
              입력하신 이메일로 인증 링크를 보내드렸습니다.
            </p>
            <div className="mb-5 rounded-lg border border-blue-200 bg-blue-50 px-4 py-3">
              <div className="flex items-center gap-1.5 text-xs font-medium text-blue-700">
                <span className="material-symbols-outlined flex-shrink-0"
                    style={{ fontSize: "14px" }}>
                  info
                </span>
                <span>메일을 확인하여 가입을 완료해주세요.</span>
              </div>
            </div>
            <div className="flex justify-end gap-3">
              <button
                type="button"
                onClick={() => navigate("/login", { replace: true })}
                className="rounded bg-primary px-5 py-2.5 text-sm font-medium text-white shadow-sm shadow-primary/30 transition hover:bg-[#1d4ed8]"
              >
                로그인하러 가기
              </button>
            </div>
          </div>
        </div>
      )}

      {/* ───── 서비스 이용약관 모달 ───── */}
      {termsModal && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4"
          onClick={(e) => {
            if (e.target === e.currentTarget) setTermsModal(false);
          }}
        >
          <div className="w-full max-w-md rounded-xl bg-white p-6 shadow-2xl">
            <div className="mb-4 flex items-center gap-3">
              <div className="flex size-10 flex-shrink-0 items-center justify-center rounded-full bg-blue-100">
                <span className="material-symbols-outlined text-xl text-blue-600">
                  description
                </span>
              </div>
              <h3 className="flex-1 text-lg font-bold text-foreground">
                서비스 이용약관
              </h3>
              <button
                type="button"
                onClick={() => setTermsModal(false)}
                className="flex-shrink-0 rounded-full p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-foreground"
              >
                <span className="material-symbols-outlined" style={{ fontSize: "20px" }}>close</span>
              </button>
            </div>
            <div className="h-72 w-full rounded-lg border border-gray-200 bg-gray-50" />
          </div>
        </div>
      )}

      {/* ───── 개인정보 처리방침 모달 ───── */}
      {privacyModal && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4"
          onClick={(e) => {
            if (e.target === e.currentTarget) setPrivacyModal(false);
          }}
        >
          <div className="w-full max-w-md rounded-xl bg-white p-6 shadow-2xl">
            <div className="mb-4 flex items-center gap-3">
              <div className="flex size-10 flex-shrink-0 items-center justify-center rounded-full bg-blue-100">
                <span className="material-symbols-outlined text-xl text-blue-600">
                  shield
                </span>
              </div>
              <h3 className="flex-1 text-lg font-bold text-foreground">
                개인정보 처리방침
              </h3>
              <button
                type="button"
                onClick={() => setPrivacyModal(false)}
                className="flex-shrink-0 rounded-full p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-foreground"
              >
                <span className="material-symbols-outlined" style={{ fontSize: "20px" }}>close</span>
              </button>
            </div>
            <div className="h-72 w-full rounded-lg border border-gray-200 bg-gray-50" />
          </div>
        </div>
      )}
    </>
  );
}
