import type { TFunction } from 'i18next'
import i18n from '../i18n'
import { humanize } from './humanize'

const splitCamelCase = (value: string) =>
  value
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
    .replace(/([a-z0-9])([A-Z])/g, '$1 $2')

export const crudLabelKey = (value?: string | null) => {
  if (!value) return ''

  return splitCamelCase(String(value))
    .replace(/&/g, ' and ')
    .replace(/[./]/g, ' ')
    .replace(/[^A-Za-z0-9_\s-]/g, '')
    .replace(/[-\s]+/g, '_')
    .replace(/_+/g, '_')
    .replace(/^_+|_+$/g, '')
    .toLowerCase()
}

const fallbackLabel = (value: string) =>
  humanize(splitCamelCase(value).replace(/_/g, ' '))
    .replace(/\bApi\b/g, 'API')
    .replace(/\bCsv\b/g, 'CSV')
    .replace(/\bHttp\b/g, 'HTTP')
    .replace(/\bId\b/g, 'ID')
    .replace(/\bKg\b/g, 'kg')
    .replace(/\bSq\b/g, 'sq')
    .replace(/\bMg\b/g, 'mg')
    .replace(/\bMm\b/g, 'mm')
    .replace(/\bNtu\b/g, 'NTU')
    .replace(/\bPh\b/g, 'pH')

export const translateCrudLabel = (value?: string | null, t?: TFunction<'common'>) => {
  if (!value) return ''

  const rawValue = String(value)
  const key = crudLabelKey(rawValue)
  const translate = t || i18n.t.bind(i18n)

  const deleteRowsMatch = rawValue.match(/^Delete\s+(\d+)\s+(Row|Rows)$/i)
  if (deleteRowsMatch) {
    return translate('crud.actions.delete_rows', {
      count: Number(deleteRowsMatch[1]),
      defaultValue: fallbackLabel(rawValue),
    })
  }

  const actionPhraseMatch = fallbackLabel(rawValue).match(/^(View|Edit|New)\s+(.+)$/i)
  if (actionPhraseMatch) {
    const actionKey = crudLabelKey(actionPhraseMatch[1])
    const entityLabel = translateCrudLabel(actionPhraseMatch[2], t)
    const actionLabel = translate(`crud.actions.${actionKey}`, {
      defaultValue: actionPhraseMatch[1],
    })

    return `${actionLabel} ${entityLabel}`.trim()
  }

  const candidates = [
    `labels.${key}`,
    `crud.actions.${key}`,
    `entities.${key}`,
    `fields.${key}`,
    `enums.${key}`,
  ]

  const match = candidates.find((candidate) => i18n.exists(candidate))

  return match ? translate(match) : fallbackLabel(rawValue)
}
