
import {
  foxValidationMessage,
  foxValidators,
  type FoxValidationMessages,
  type FoxValidator,
} from '@fox/core/validation';
import {
  ADMIN_ROLE_OPTIONS,
  type AdminRoleCode,
} from '@/lib/domain/admin-member';

export const ADMIN_LOGIN_ID_HELP_TEXT =
  '영어 소문자, 숫자를 조합하여 입력 후 중복여부를 확인하세요.';
export const ADMIN_PASSWORD_HELP_TEXT =
  '영어, 숫자, 특수문자 중 2종류 이상 조합, 최소 10자리 이상';

export const ADMIN_PASSWORD_ERROR_TEXT =
  '비밀번호가 규칙에 맞지 않습니다. 영어·숫자·특수문자 중 2종류 이상으로 10자리 이상 입력해 주세요.';

const LOGIN_ID_MIN_LENGTH = 4;
const LOGIN_ID_MAX_LENGTH = 20;

export const ADMIN_LOGIN_ID_VALIDATORS: FoxValidator[] = [
  foxValidators.required,
  foxValidators.minLength(LOGIN_ID_MIN_LENGTH),
  foxValidators.maxLength(LOGIN_ID_MAX_LENGTH),
  foxValidators.pattern(/^[a-z0-9]+$/),
  foxValidators.characterKinds(2),
];

export const ADMIN_LOGIN_ID_MESSAGES: FoxValidationMessages = {
  required: 'ID를 입력해 주세요.',
  minlength: `ID는 ${LOGIN_ID_MIN_LENGTH}~${LOGIN_ID_MAX_LENGTH}자로 입력해 주세요.`,
  maxlength: `ID는 ${LOGIN_ID_MIN_LENGTH}~${LOGIN_ID_MAX_LENGTH}자로 입력해 주세요.`,
  pattern: ADMIN_LOGIN_ID_HELP_TEXT,
  characterKinds: ADMIN_LOGIN_ID_HELP_TEXT,
};

export const ADMIN_PASSWORD_POLICY = {
  minLength: 10,
  kinds: 2,
} as const;
const NAME_MAX_LENGTH = 50;
const EMAIL_MAX_LENGTH = 100;

export function adminEmailValidators(required: boolean): FoxValidator[] {
  return [
    ...(required ? [foxValidators.required] : []),
    foxValidators.email,
    foxValidators.maxLength(EMAIL_MAX_LENGTH),
  ];
}

export const ADMIN_EMAIL_MESSAGES: FoxValidationMessages = {
  required: '이메일을 입력해 주세요.',
  email: '이메일 형식이 올바르지 않습니다.',
  maxlength: `이메일은 ${EMAIL_MAX_LENGTH}자 이내로 입력해 주세요.`,
};

const PHONE_DIGITS_PATTERN = /^(\d{3})(\d{3,4})(\d{4})$/;

export type AdminMemberEditableValues = {
  password: string;
  phoneNumber: string;
  email: string;
  roleCode: AdminRoleCode;
};

export type AdminMemberCreateValues = AdminMemberEditableValues & {
  name: string;
  loginId: string;
};

export type AdminMemberFormErrors = Partial<
  Record<keyof AdminMemberCreateValues, string>
>;

export type ValidationResult<T> =
  | { ok: true; values: T }
  | { ok: false; errors: AdminMemberFormErrors };

export type AdminMemberFormState =
  | { status: 'idle' }
  | { status: 'error'; message?: string; errors?: AdminMemberFormErrors }
  | { status: 'success' };

export const INITIAL_ADMIN_MEMBER_FORM_STATE: AdminMemberFormState = {
  status: 'idle',
};

function countCharacterKinds(password: string): number {
  const kinds = [/[a-zA-Z]/, /\d/, /[^a-zA-Z0-9]/];
  return kinds.filter((pattern) => pattern.test(password)).length;
}

export function validateAdminLoginId(loginId: string): string | null {
  const errors = foxValidators.compose(ADMIN_LOGIN_ID_VALIDATORS)(loginId.trim());
  return foxValidationMessage(errors, ADMIN_LOGIN_ID_MESSAGES) ?? null;
}

export function formatPhoneNumber(digits: string): string | null {
  const matched = PHONE_DIGITS_PATTERN.exec(digits.trim());
  return matched === null ? null : `${matched[1]}-${matched[2]}-${matched[3]}`;
}

export function toPhoneDigits(phoneNumber: string | null): string {
  return (phoneNumber ?? '').replace(/\D/g, '');
}

function validateEditableValues(
  values: AdminMemberEditableValues,
  errors: AdminMemberFormErrors,
  options: { passwordRequired: boolean; emailRequired: boolean }
): AdminMemberEditableValues {
  const password = values.password;
  const phoneNumber = values.phoneNumber.trim();
  const email = values.email.trim();

  if (!password) {
    if (options.passwordRequired) {
      errors.password = ADMIN_PASSWORD_ERROR_TEXT;
    }
  } else if (
    password.length < ADMIN_PASSWORD_POLICY.minLength ||
    countCharacterKinds(password) < ADMIN_PASSWORD_POLICY.kinds
  ) {
    errors.password = ADMIN_PASSWORD_ERROR_TEXT;
  }

  if (!phoneNumber) {
    errors.phoneNumber = '휴대전화 번호를 정확히 입력해 주세요.';
  }

  const emailError = foxValidationMessage(
    foxValidators.compose(adminEmailValidators(options.emailRequired))(email),
    ADMIN_EMAIL_MESSAGES
  );
  if (emailError) {
    errors.email = emailError;
  }

  if (!ADMIN_ROLE_OPTIONS.some((option) => option.value === values.roleCode)) {
    errors.roleCode = '역할을 선택해 주세요.';
  }

  return { password, phoneNumber, email, roleCode: values.roleCode };
}

export function validateAdminMemberCreate(
  values: AdminMemberCreateValues
): ValidationResult<AdminMemberCreateValues> {
  const errors: AdminMemberFormErrors = {};

  const name = values.name.trim();
  if (!name) {
    errors.name = '이름을 입력해 주세요.';
  } else if (name.length > NAME_MAX_LENGTH) {
    errors.name = `이름은 ${NAME_MAX_LENGTH}자 이내로 입력해 주세요.`;
  }

  const loginIdError = validateAdminLoginId(values.loginId);
  if (loginIdError) {
    errors.loginId = loginIdError;
  }

  const editable = validateEditableValues(values, errors, {
    passwordRequired: true,
    emailRequired: true,
  });

  if (Object.keys(errors).length > 0) {
    return { ok: false, errors };
  }

  return {
    ok: true,
    values: { ...editable, name, loginId: values.loginId.trim() },
  };
}

export function validateAdminMemberUpdate(
  values: AdminMemberEditableValues
): ValidationResult<AdminMemberEditableValues> {
  const errors: AdminMemberFormErrors = {};

  const editable = validateEditableValues(values, errors, {
    passwordRequired: false,
    emailRequired: false,
  });

  if (Object.keys(errors).length > 0) {
    return { ok: false, errors };
  }

  return { ok: true, values: editable };
}
