'use client';

import {
  useActionState,
  useEffect,
  useRef,
  useState,
  useTransition,
} from 'react';
import { FoxButton } from '@fox/core/components/fox-button';
import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
import { FoxFormLabel } from '@fox/core/components/fox-form-label';
import { FoxInput } from '@fox/core/components/fox-input';
import { FoxSelect } from '@fox/core/components/fox-select';
import { FoxModal } from '@fox/core/components/fox-modal';
import { foxPasswordValidator } from '@fox/core/validation';
import { FoxChatCenteredDotsIcon } from '@fox/core/icons';
import { useFeedback } from '@/app/_hooks/use-feedback';
import { DEFAULT_ADMIN_ROLE_CODE } from '@/lib/domain/admin-member';
import {
  ADMIN_LOGIN_ID_HELP_TEXT,
  ADMIN_PASSWORD_HELP_TEXT,
  ADMIN_PASSWORD_POLICY,
  INITIAL_ADMIN_MEMBER_FORM_STATE,
} from '@/lib/domain/admin-member-form';
import {
  checkAdminLoginId,
  createAdminMemberAction,
  type LoginIdCheckResult,
} from '../_actions';
import { AdminMemberFormFields } from './admin-member-form-fields';
import styles from './admin-member-modal.module.scss';

interface AdminMemberCreateModalProps {
  onClose: () => void;
}

/** 목록에 없는 주소를 위해 도메인 칸을 입력으로 바꾸는 값. 실제 도메인과 겹치지 않게 잡았다. */
const CUSTOM_EMAIL_DOMAIN = '__custom__';

/** 시안의 도메인 목록. 맨 아래 "직접입력"은 같은 칸을 입력으로 바꾼다(상자를 늘리지 않는다). */
const EMAIL_DOMAIN_OPTIONS = [
  'naver.com',
  'gmail.com',
  'daum.net',
  'hanmail.net',
  'nate.com',
];

/**
 * 관리자 등록 팝업 — 시안: 관리자페이지(QsFVFFUKGH68xAPVkF3SJ9) ADM_ADM_102_p (5227:2035)
 *
 * **ID는 중복 확인을 통과해야 저장할 수 있다**(시안 ①). 확인은 등록 폼과 별개의 서버 호출인데,
 * 폼 안에 폼을 중첩할 수 없어 `useActionState` 대신 값을 직접 넘기는 Server Action
 * (`checkAdminLoginId`)을 `useTransition`으로 호출한다. 확인 후 사용자가 ID를 고칠 수 있으므로
 * "확인에 성공한 ID"와 "지금 입력창의 값"이 같을 때만 통과로 본다 — 확인만 받아 두고 다른 ID로
 * 바꿔 저장하는 경로를 막기 위해서다. 그래도 최종 방어선은 Server Action의 재확인이다.
 *
 * 저장 버튼은 `FoxModal`의 actions 슬롯에 있어 폼 **바깥**에 그려진다. `FoxButton`에는 네이티브
 * `form` 속성이 없으므로 폼을 ref로 잡아 `requestSubmit()`을 부른다 — `useActionState`의 폼
 * 액션이 그대로 타는 정식 제출이라 검증·상태 흐름이 동일하다.
 *
 * @fox의 제어 위젯(전화번호·이메일·역할·메뉴)은 값이 FormData에 실리지 않아 이 컴포넌트가 값을
 * 들고 hidden input으로 제출한다(`AdminMemberFormFields` 주석 참조).
 *
 * 비밀번호는 형식만 검증하고 백엔드가 SHA-256으로 암호화해 저장한다(`MngrAdminServiceImpl`).
 */
export function AdminMemberCreateModal({
  onClose,
}: AdminMemberCreateModalProps) {
  const { showToast } = useFeedback();
  const [state, formAction, isPending] = useActionState(
    createAdminMemberAction,
    INITIAL_ADMIN_MEMBER_FORM_STATE
  );
  const formRef = useRef<HTMLFormElement>(null);

  const [loginId, setLoginId] = useState('');
  const [checkResult, setCheckResult] = useState<LoginIdCheckResult>({
    status: 'idle',
  });
  const [isChecking, startChecking] = useTransition();

  const [phoneNumber, setPhoneNumber] = useState('');
  const [emailLocal, setEmailLocal] = useState('');
  const [emailDomain, setEmailDomain] = useState(EMAIL_DOMAIN_OPTIONS[0]);
  const [isCustomDomain, setIsCustomDomain] = useState(false);
  const [roleCode, setRoleCode] = useState<string>(DEFAULT_ADMIN_ROLE_CODE);
  const [menuCodes, setMenuCodes] = useState<string[]>([]);

  useEffect(() => {
    if (state.status === 'success') {
      showToast({ variant: 'success', message: '관리자를 등록했습니다.' });
      onClose();
    }
  }, [state, showToast, onClose]);

  const isLoginIdVerified =
    checkResult.status === 'available' && checkResult.loginId === loginId.trim();

  const errors = state.status === 'error' ? (state.errors ?? {}) : {};

  const email = emailLocal || emailDomain ? `${emailLocal}@${emailDomain}` : '';

  // 중복 확인 결과는 서버 검증 오류보다 먼저 보여준다 — 방금 누른 버튼의 답이기 때문이다.
  // 값이 나쁜 것(unavailable)과 확인을 못 한 것(failed)은 사유가 다르므로 둘 다 문구로 낸다.
  const loginIdFailure =
    checkResult.status === 'unavailable' || checkResult.status === 'failed'
      ? checkResult.message
      : undefined;
  const loginIdMessage =
    loginIdFailure ??
    (isLoginIdVerified
      ? '사용할 수 있는 ID입니다.'
      : (errors.loginId ?? ADMIN_LOGIN_ID_HELP_TEXT));

  return (
    <FoxModal
      open
      onClose={onClose}
      size="sm"
      title="관리자 등록"
      actions={
        <FoxButtonGroup size="md">
          <FoxButton type="default" size="md" label="취소" onAction={onClose} />
          <FoxButton
            type="primary"
            size="md"
            label="저장"
            loading={isPending}
            disabled={!isLoginIdVerified}
            onAction={() => formRef.current?.requestSubmit()}
          />
        </FoxButtonGroup>
      }
    >
      <form ref={formRef} action={formAction} className={styles.formList}>
        <FoxInput
          size="md"
          name="name"
          label="이름"
          requirement="required"
          placeholder="이름을 입력하세요."
          message={errors.name}
          invalid={Boolean(errors.name)}
        />

        <div className={styles.fieldWithAction}>
          <FoxInput
            size="md"
            name="loginId"
            label="ID"
            requirement="required"
            placeholder="관리자 ID를 입력하세요."
            autoComplete="off"
            value={loginId}
            onChange={setLoginId}
            message={loginIdMessage}
            messageIcon={<FoxChatCenteredDotsIcon />}
            invalid={Boolean(loginIdFailure) || Boolean(errors.loginId)}
          />
          <FoxButton
            type="secondary"
            size="md"
            fullWidth
            label="중복 확인"
            loading={isChecking}
            disabled={loginId.trim().length === 0}
            onAction={() =>
              startChecking(async () => {
                try {
                  setCheckResult(await checkAdminLoginId(loginId));
                } catch {
                  // Server Action 호출 자체가 깨진 경우(네트워크 등). 조용히 끝나면 버튼만
                  // 원복되고 아무 말도 남지 않아, 사유를 알 수 없어도 실패는 알린다.
                  setCheckResult({
                    status: 'failed',
                    message: '중복 확인에 실패했습니다. 잠시 후 다시 시도해 주세요.',
                  });
                }
              })
            }
          />
        </div>

        <FoxInput
          size="md"
          type="password"
          name="password"
          label="비밀번호"
          requirement="required"
          placeholder="비밀번호를 입력하세요."
          autoComplete="new-password"
          message={errors.password ?? ADMIN_PASSWORD_HELP_TEXT}
          messageIcon={<FoxChatCenteredDotsIcon />}
          invalid={Boolean(errors.password)}
          // 규칙은 도메인이 한 벌로 갖는다 — 저장 직전 서버 검증이 같은 값을 본다.
          validators={[foxPasswordValidator({ ...ADMIN_PASSWORD_POLICY, required: true })]}
          validationMessages={{ minlength: ADMIN_PASSWORD_HELP_TEXT }}
        />

        <AdminMemberFormFields
          phoneNumber={phoneNumber}
          onPhoneNumberChange={setPhoneNumber}
          roleCode={roleCode}
          onRoleCodeChange={setRoleCode}
          menuCodes={menuCodes}
          onMenuCodesChange={setMenuCodes}
          errors={errors}
          emailField={
            <>
              <div className={styles.field}>
                <FoxFormLabel as="span" requirement="required">
                  이메일
                </FoxFormLabel>
                <div className={styles.emailRow}>
                  <span className={styles.emailPart}>
                    <FoxInput
                      size="md"
                      aria-label="이메일 아이디"
                      placeholder="1234-5678"
                      value={emailLocal}
                      onChange={setEmailLocal}
                      invalid={Boolean(errors.email)}
                    />
                  </span>
                  <span aria-hidden="true">@</span>
                  <span className={styles.emailPart}>
                    {isCustomDomain ? (
                      <FoxInput
                        size="md"
                        aria-label="이메일 도메인"
                        placeholder="직접입력"
                        value={emailDomain}
                        onChange={setEmailDomain}
                        invalid={Boolean(errors.email)}
                      />
                    ) : (
                      <FoxSelect
                        size="md"
                        options={[
                          ...EMAIL_DOMAIN_OPTIONS.map((domain) => ({
                            value: domain,
                            label: domain,
                          })),
                          { value: CUSTOM_EMAIL_DOMAIN, label: '직접입력' },
                        ]}
                        value={emailDomain}
                        onValueChange={(next) => {
                          if (next === CUSTOM_EMAIL_DOMAIN) {
                            setIsCustomDomain(true);
                            setEmailDomain('');
                            return;
                          }
                          setEmailDomain(next);
                        }}
                        error={Boolean(errors.email)}
                      />
                    )}
                  </span>
                </div>
                {errors.email && <p role="alert">{errors.email}</p>}
              </div>
              <input type="hidden" name="email" value={email} />
            </>
          }
        />

        {state.status === 'error' && state.message && (
          <p role="alert">{state.message}</p>
        )}
      </form>
    </FoxModal>
  );
}
