import type { FoxValidationErrors } from './fox-validators';

type MessageFactory = (detail: unknown) => string;

function detailOf<T>(detail: unknown): T {
  return detail as T;
}

const DEFAULT_MESSAGES: Record<string, MessageFactory> = {
  required: () => '필수 입력 항목입니다.',
  minlength: (detail) =>
    `${detailOf<{ requiredLength: number }>(detail).requiredLength}자 이상 입력해 주세요.`,
  maxlength: (detail) =>
    `${detailOf<{ requiredLength: number }>(detail).requiredLength}자 이내로 입력해 주세요.`,
  pattern: () => '형식이 올바르지 않습니다.',
  email: () => '이메일 형식이 올바르지 않습니다.',
  characterKinds: (detail) =>
    `영문, 숫자, 특수문자 중 ${
      detailOf<{ requiredKinds: number }>(detail).requiredKinds
    }종류 이상을 섞어 주세요.`,
  repeatedCharacters: (detail) =>
    `같은 문자를 ${detailOf<{ max: number }>(detail).max}번까지만 연달아 쓸 수 있습니다.`,
  sequentialCharacters: (detail) =>
    `연속된 문자나 숫자를 ${
      detailOf<{ max: number }>(detail).max
    }자를 넘겨 쓸 수 없습니다.`,
  notContaining: (detail) =>
    `${detailOf<{ forbidden: string }>(detail).forbidden}은(는) 포함할 수 없습니다.`,
  equalTo: () => '값이 일치하지 않습니다.',
};

const MESSAGE_ORDER = [
  'required',
  'minlength',
  'maxlength',
  'pattern',
  'email',
  'characterKinds',
  'repeatedCharacters',
  'sequentialCharacters',
  'notContaining',
  'equalTo',
];

export type FoxValidationMessages = Record<
  string,
  string | ((detail: unknown) => string)
>;

export function foxValidationMessage(
  errors: FoxValidationErrors | null,
  overrides: FoxValidationMessages = {}
): string | undefined {
  if (!errors) {
    return undefined;
  }

  const keys = Object.keys(errors);
  const ordered = [
    ...MESSAGE_ORDER.filter((key) => keys.includes(key)),
    ...keys.filter((key) => !MESSAGE_ORDER.includes(key)),
  ];

  for (const key of ordered) {
    const override = overrides[key];
    if (typeof override === 'string') {
      return override;
    }
    if (typeof override === 'function') {
      return override(errors[key]);
    }
    const fallback = DEFAULT_MESSAGES[key];
    if (fallback) {
      return fallback(errors[key]);
    }
  }
  return undefined;
}
