import type { I18nString } from '@pikku/react'
import arMessages from '../messages/ar.json'
import bsMessages from '../messages/bs.json'
import deMessages from '../messages/de.json'
import enMessages from '../messages/en.json'
import esMessages from '../messages/es.json'
import filMessages from '../messages/fil.json'
import hiMessages from '../messages/hi.json'
import sqMessages from '../messages/sq.json'
import trMessages from '../messages/tr.json'
import ukMessages from '../messages/uk.json'
import viMessages from '../messages/vi.json'
import { defaultLocale, getLocale, maskI18n, type Locale } from './config'
import { identOf } from './ident'

type MessageCatalog = Record<string, string>
type MessageArgs = Record<string, unknown>
type MessageFn = (args?: MessageArgs) => I18nString

const catalogs: Record<Locale, MessageCatalog> = {
  ar: arMessages as MessageCatalog,
  bs: bsMessages as MessageCatalog,
  de: deMessages as MessageCatalog,
  en: enMessages as MessageCatalog,
  es: esMessages as MessageCatalog,
  fil: filMessages as MessageCatalog,
  hi: hiMessages as MessageCatalog,
  sq: sqMessages as MessageCatalog,
  tr: trMessages as MessageCatalog,
  uk: ukMessages as MessageCatalog,
  vi: viMessages as MessageCatalog,
}

const interpolate = (template: string, args?: MessageArgs) =>
  template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_match, key: string) => {
    const value = args?.[key]
    return value === undefined || value === null ? '' : String(value)
  })

const getMessageValue = (key: string, locale = getLocale()) =>
  catalogs[locale]?.[key] ?? catalogs[defaultLocale]?.[key]

const toI18n = (value: string) => maskI18n(value) as unknown as I18nString

const parseListValue = (value: string): string[] => {
  try {
    const parsed = JSON.parse(value) as unknown
    if (Array.isArray(parsed)) {
      return parsed.map((item) => String(item))
    }
  } catch {
    // Fall through to a permissive parser for malformed copied JSON.
  }

  return value
    .replace(/^\s*\[/, '')
    .replace(/\]\s*$/, '')
    .split(/","|"،\s*"|»,\s*«|",\s*"/)
    .map((item) => item.replace(/^["«\s]+|["»\s]+$/g, '').trim())
    .filter(Boolean)
}

const getIndexedList = (keyPrefix: string): string[] => {
  const values: string[] = []
  for (let index = 0; ; index += 1) {
    const value = getMessageValue(`${keyPrefix}_${index}`)
    if (!value) {
      break
    }
    values.push(value)
  }
  return values
}

export const mKey = (key: string, args?: MessageArgs): I18nString => {
  const value = getMessageValue(identOf(key))
  if (!value) {
    if (typeof console !== 'undefined') {
      console.warn(`[i18n] missing message for key "${key}"`)
    }
    return toI18n(key)
  }

  return toI18n(interpolate(value, args))
}

// Plain-string resolution in an explicit locale (no active-locale store).
// For server-side, locale-parameterized text like SEO meta tags.
export const mTextIn = (
  locale: Locale,
  key: string,
  args?: MessageArgs,
): string => {
  const value = getMessageValue(identOf(key), locale)
  return value ? interpolate(value, args) : key
}

export const mList = (keyPrefix: string, args?: MessageArgs): I18nString[] => {
  const ident = identOf(keyPrefix)
  const indexedValues = getIndexedList(ident)
  const values =
    indexedValues.length > 0
      ? indexedValues
      : (() => {
          const exactValue = getMessageValue(ident)
          return exactValue ? parseListValue(exactValue) : []
        })()

  return values.map((value) => toI18n(interpolate(value, args)))
}

export const m = new Proxy(
  {},
  {
    get: (_target, property) => {
      if (typeof property !== 'string') {
        return undefined
      }

      const fn: MessageFn = (args) => {
        const value = getMessageValue(property)
        return toI18n(interpolate(value ?? property, args))
      }

      return fn
    },
  },
) as Record<string, MessageFn>
