/**
 * The translation function, shared by server and client.
 *
 * Deliberately tiny: a dot-path lookup with `{placeholder}` interpolation. A missing key
 * returns the key itself rather than throwing or rendering blank, so a gap in a
 * translation file shows up immediately in the UI instead of silently producing an empty
 * label in a control room.
 */

import { INTL_LOCALE, type Locale } from './config'

export type Messages = Record<string, unknown>

export type TranslateParams = Record<string, string | number>

export function lookup(messages: Messages, key: string): string | undefined {
  const parts = key.split('.')
  let current: unknown = messages
  for (const part of parts) {
    if (typeof current !== 'object' || current === null) return undefined
    current = (current as Record<string, unknown>)[part]
  }
  return typeof current === 'string' ? current : undefined
}

export function interpolate(template: string, params?: TranslateParams): string {
  if (!params) return template
  return template.replace(/\{(\w+)\}/g, (match, name: string) =>
    name in params ? String(params[name]) : match,
  )
}

export type Translator = (key: string, params?: TranslateParams) => string

export function createTranslator(messages: Messages): Translator {
  return (key, params) => {
    const template = lookup(messages, key)
    if (template === undefined) {
      if (process.env.NODE_ENV !== 'production') {
        console.warn(`[i18n] missing key: ${key}`)
      }
      return key
    }
    return interpolate(template, params)
  }
}

// ─────────────────────────────────────────────────────────────────────────────
// Formatting
// ─────────────────────────────────────────────────────────────────────────────

const numberFormatters = new Map<string, Intl.NumberFormat>()

function numberFormatter(locale: Locale, options: Intl.NumberFormatOptions): Intl.NumberFormat {
  const key = `${locale}:${JSON.stringify(options)}`
  let formatter = numberFormatters.get(key)
  if (!formatter) {
    formatter = new Intl.NumberFormat(INTL_LOCALE[locale], options)
    numberFormatters.set(key, formatter)
  }
  return formatter
}

export function formatNumber(
  locale: Locale,
  value: number,
  options: Intl.NumberFormatOptions = {},
): string {
  if (!Number.isFinite(value)) return '—'
  return numberFormatter(locale, options).format(value)
}

/** Megawatts with a sensible precision band: whole numbers when large, one decimal when small. */
export function formatMw(locale: Locale, value: number): string {
  const abs = Math.abs(value)
  const digits = abs >= 1000 ? 0 : abs >= 100 ? 0 : 1
  return formatNumber(locale, value, { maximumFractionDigits: digits, minimumFractionDigits: digits })
}

export function formatPercent(locale: Locale, value: number, digits = 0): string {
  return `${formatNumber(locale, value, { maximumFractionDigits: digits, minimumFractionDigits: digits })}%`
}

export function formatDateTime(
  locale: Locale,
  value: Date | number,
  options: Intl.DateTimeFormatOptions = {
    dateStyle: 'medium',
    timeStyle: 'short',
  },
): string {
  return new Intl.DateTimeFormat(INTL_LOCALE[locale], {
    timeZone: 'Asia/Riyadh',
    ...options,
  }).format(value)
}

export function formatTime(locale: Locale, value: Date | number): string {
  return formatDateTime(locale, value, { hour: '2-digit', minute: '2-digit', hour12: false })
}

export function formatDate(locale: Locale, value: Date | number): string {
  return formatDateTime(locale, value, { dateStyle: 'medium' })
}

/**
 * Duration in minutes rendered as a compact human string ("43 min", "2 h 15 min").
 * Uses the translator so the units follow the active language.
 */
export function formatDuration(t: Translator, minutes: number): string {
  const abs = Math.max(0, Math.round(minutes))
  if (abs < 60) return t('common.duration.minutes', { value: abs })
  const hours = Math.floor(abs / 60)
  const rest = abs % 60
  if (abs < 1440) {
    return rest === 0
      ? t('common.duration.hours', { value: hours })
      : t('common.duration.hoursMinutes', { hours, minutes: rest })
  }
  const days = Math.floor(abs / 1440)
  const restHours = Math.floor((abs % 1440) / 60)
  return restHours === 0
    ? t('common.duration.days', { value: days })
    : t('common.duration.daysHours', { days, hours: restHours })
}

/** Relative time such as "12 minutes ago" / "قبل ١٢ دقيقة". */
export function formatRelative(locale: Locale, value: Date | number, now = Date.now()): string {
  const diffMs = (typeof value === 'number' ? value : value.getTime()) - now
  const formatter = new Intl.RelativeTimeFormat(INTL_LOCALE[locale], { numeric: 'auto' })
  const units: Array<[Intl.RelativeTimeFormatUnit, number]> = [
    ['year', 31_536_000_000],
    ['month', 2_592_000_000],
    ['day', 86_400_000],
    ['hour', 3_600_000],
    ['minute', 60_000],
    ['second', 1000],
  ]
  for (const [unit, ms] of units) {
    if (Math.abs(diffMs) >= ms || unit === 'second') {
      return formatter.format(Math.round(diffMs / ms), unit)
    }
  }
  return formatter.format(0, 'second')
}
