// i18n configuration — Paraglide JS (inlang). Messages live in `messages/*.json`
// and are compiled to `src/paraglide/` by the Vite plugin (gitignored). This
// module is the locale-plumbing entry point; `@/i18n/messages` exposes the typed
// message functions (`m`).
//
// Add a language: drop `messages/<lang>.json` next to `en.json`, add the code to
// `project.inlang/settings.json` `locales`, and recompile. Content is reachable
// via the `/<lang>` URL prefix (e.g. `/fr`); the base locale (`en`) needs none.
import { useSyncExternalStore } from 'react'
import { locales, baseLocale, overwriteGetLocale, getLocale } from '../paraglide/runtime.js'

export const supportedLocales = locales
export const defaultLocale = baseLocale
export type Locale = (typeof locales)[number]
// `getLocale()` reads the active locale (via the overwrite below) — used by
// pages that format dates/values for the current language.
export { getLocale }

const LANGUAGE_STORAGE_KEY = 'germantax.language'

const RTL_LOCALES = new Set(['ar', 'he', 'fa', 'ur'])
// Direction for a locale — RTL for Arabic/Hebrew/Farsi/Urdu, else LTR. Set this
// on <html dir> at the root so the browser (and Mantine) mirror the layout.
export function localeDir(locale: string = defaultLocale): 'rtl' | 'ltr' {
  return RTL_LOCALES.has(locale.split('-')[0]) ? 'rtl' : 'ltr'
}

const normalizeLanguage = (value: string | null | undefined): Locale | undefined => {
  const short = value?.slice(0, 2).toLowerCase()
  return supportedLocales.includes(short as Locale) ? (short as Locale) : undefined
}

// Initial locale: persisted choice → browser → <html lang> → base. (Ported from
// the old i18next init; germantax has no in-app switcher, locale is read once.)
export function detectInitialLocale(): Locale {
  if (typeof window === 'undefined') return defaultLocale
  return (
    normalizeLanguage(window.localStorage.getItem(LANGUAGE_STORAGE_KEY)) ??
    normalizeLanguage(window.navigator.language) ??
    normalizeLanguage(window.document.documentElement.lang) ??
    defaultLocale
  )
}

// ── reactive locale store ────────────────────────────────────────────────────
// Paraglide's `getLocale()` is a module-global, decoupled from React. We bridge
// it to a tiny external store: `getLocale` reads `activeLocale`; components
// subscribe via `useLocale()` (useSyncExternalStore) so `m.*()` re-renders on
// switch — no page reload, no Paraglide `setLocale`, no app-specific context.
// The app's own setLocale (persist + <html dir>) calls `setActiveLocale`.
let activeLocale: Locale = defaultLocale
const listeners = new Set<() => void>()
overwriteGetLocale(() => activeLocale)

export function setActiveLocale(next: Locale): void {
  if (next === activeLocale) return
  activeLocale = next
  // Persist + reflect on <html lang> (ported from the old i18next languageChanged
  // handler), so a reload restores the choice.
  if (typeof window !== 'undefined') {
    window.localStorage.setItem(LANGUAGE_STORAGE_KEY, next)
    window.document.documentElement.lang = next
  }
  for (const fn of listeners) fn()
}

function subscribe(fn: () => void): () => void {
  listeners.add(fn)
  return () => listeners.delete(fn)
}

// Resolve the initial locale once at startup (import side-effect, matching the
// old i18n.ts init). Importing this module from the app entry runs it.
activeLocale = detectInitialLocale()

// Subscribe a component to locale changes so `m.*()` re-renders on switch. The
// codemod injects a bare `useLocale()` wherever `const { t } = useTranslation()`
// used to live; it also returns the active locale + direction for components
// that need them (e.g. the language switcher).
export function useLocale(): { locale: Locale; dir: 'ltr' | 'rtl'; setLocale: (l: Locale) => void } {
  const locale = useSyncExternalStore<Locale>(subscribe, () => activeLocale, () => activeLocale)
  return { locale, dir: localeDir(locale), setLocale: setActiveLocale }
}

// ── i18n-debug masking ───────────────────────────────────────────────────────
// When enabled, every *translated* string is masked to block glyphs (█) so any
// readable text left on screen is text that never went through a message (a
// hardcoded/inlined string) — missing i18n at a glance. Toggle with `?i18n-debug`
// in the URL or `localStorage['i18n-debug'] = '1'` (`I18N_DEBUG=1` for SSR).
export function isI18nDebug(): boolean {
  if (typeof process !== 'undefined' && process.env?.I18N_DEBUG === '1') return true
  if (typeof window === 'undefined') return false
  const params = new URLSearchParams(window.location.search)
  if (params.has('i18n-debug')) return params.get('i18n-debug') !== '0'
  return window.localStorage?.getItem('i18n-debug') === '1'
}

/** Mask a rendered string when debug mode is on; otherwise pass it through. */
export function maskI18n(s: string): string {
  return isI18nDebug() ? s.replace(/\S/g, '█') : s
}
