import type { ZodErrorMap } from 'zod'

export type ZodMessageKey =
  | 'required'
  | 'invalid_type'
  | 'too_small_string'
  | 'too_big_string'
  | 'too_small_number'
  | 'too_big_number'
  | 'invalid_string_email'
  | 'invalid_string_url'
  | 'invalid_enum_value'
  | 'invalid_date'
  | 'custom'

export type ZodMessages = Record<ZodMessageKey, string>

export type ZodTranslateFn = (key: ZodMessageKey) => string

function resolveMessages(source: ZodMessages | ZodTranslateFn): ZodTranslateFn {
  if (typeof source === 'function') return source
  const msgs = source
  return (key) => msgs[key]
}

export function createZodErrorMap(source: ZodMessages | ZodTranslateFn): ZodErrorMap {
  const m = resolveMessages(source)
  return (issue) => {
    switch (issue.code) {
      case 'invalid_type':
        if (issue.input === undefined) return { message: m('required') }
        if (issue.expected === 'date') return { message: m('invalid_date') }
        return { message: m('invalid_type') }
      case 'too_small':
        return {
          message: issue.origin === 'string' ? m('too_small_string') : m('too_small_number'),
        }
      case 'too_big':
        return {
          message: issue.origin === 'string' ? m('too_big_string') : m('too_big_number'),
        }
      case 'invalid_format': {
        const format = (issue as { format?: string }).format
        if (format === 'email') return { message: m('invalid_string_email') }
        if (format === 'url') return { message: m('invalid_string_url') }
        return { message: m('invalid_type') }
      }
      case 'invalid_value':
        return { message: m('invalid_enum_value') }
      case 'custom':
        return { message: m('custom') }
      default:
        return undefined
    }
  }
}
