/**
 * i18n module for biblatex-csl-converter
 *
 * Provides human-readable labels for reference types, field names, field help
 * text, and option values in multiple languages.
 *
 * ## Structure of a locale object
 * ```json
 * {
 *   "fieldTitles":       { "<fieldKey>": "<label>", … },
 *   "fieldHelp":         { "<fieldKey>": "<help text>", … },
 *   "typeTitles":        { "<typeKey>":  "<label>", … },
 *   "fieldTitlesByType": { "<typeKey>":  { "<fieldKey>": "<label>" }, … },
 *   "langidOptions":     { "<langidKey>": "<label>", … },
 *   "otherOptions":      { "<optionKey>": "<label>", … }
 * }
 * ```
 *
 * ## Per-type field overrides (`fieldTitlesByType`)
 * Some field names carry a different human meaning depending on the reference
 * type.  For example, the `author` field of a `video` entry is conventionally
 * labelled "Director(s)" rather than "Author(s)".  Use `getFieldTitle()` which
 * checks `fieldTitlesByType[type][field]` first and falls back to
 * `fieldTitles[field]`.
 *
 * ## Option split
 * `langidOptions` covers every value valid for the BibLaTeX `langid` field
 * (including BibTeX-level aliases such as `pinyin`, `american`, `english`).
 * `otherOptions` covers editortype values, pagination values, pubstate values,
 * and `type` sub-field values (mathesis, phdthesis, techreport, …).
 *
 * ## Locale data
 * The locale data lives in `src/i18n/locales.ts`, which is auto-generated by:
 *   npm run compile_i18n
 *
 * ## Supported languages
 * ar, bg, cs, de, en, es, fr, it, ja, ko, nl, pl, pt-BR, pt-PT, ru, sv, tr, zh
 */

// ---------------------------------------------------------------------------
// Types (re-exported from ./types.ts to keep the public API stable)
// ---------------------------------------------------------------------------

export type {
    FieldHelp,
    FieldTitles,
    FieldTitlesByType,
    LangidOptions,
    Locale,
    OtherOptions,
    TypeTitles,
} from "./types"

import type { Locale } from "./types"

// ---------------------------------------------------------------------------
// Locale registry
// ---------------------------------------------------------------------------

import {
    ar,
    bg,
    cs,
    da,
    de,
    en,
    es,
    fr,
    it,
    ja,
    ko,
    nb,
    nl,
    pl,
    ptBR,
    ptPT,
    ru,
    sv,
    tr,
    zh,
} from "./locales"

export {
    ar,
    bg,
    cs,
    da,
    de,
    en,
    es,
    fr,
    it,
    ja,
    ko,
    nb,
    nl,
    pl,
    ptBR,
    ptPT,
    ru,
    sv,
    tr,
    zh,
}

/**
 * All built-in locales keyed by IETF language tag.
 *
 * Consumers that need a language not listed here can supply their own `Locale`
 * object — every public helper accepts a `Locale` directly.
 */
export const locales: Readonly<Record<string, Locale>> = Object.freeze({
    ar,
    bg,
    cs,
    da,
    de,
    en,
    es,
    fr,
    it,
    ja,
    ko,
    nl,
    nb,
    pl,
    "pt-BR": ptBR,
    "pt-PT": ptPT,
    ru,
    sv,
    tr,
    zh,
})

// ---------------------------------------------------------------------------
// Helper functions
// ---------------------------------------------------------------------------

/**
 * Return the `Locale` for *lang*, falling back to English when not available.
 *
 * Lookup order:
 * 1. Exact tag (e.g. `"pt-BR"`)
 * 2. Base subtag (e.g. `"pt"` from `"pt-BR"`)
 * 3. English fallback
 *
 * @example
 * getLocale("de")       // → locales.de
 * getLocale("pt-BR")    // → locales["pt-BR"]
 * getLocale("zh")       // → locales.en  (fallback)
 */
export function getLocale(lang: string): Locale {
    if (lang in locales) {
        return locales[lang]
    }
    const base = lang.split("-")[0]
    if (base !== lang && base in locales) {
        return locales[base]
    }
    return locales.en
}

/**
 * Return the human-readable label for *fieldKey* in the context of *typeKey*,
 * using *locale* for the translation.
 *
 * Checks `locale.fieldTitlesByType[typeKey][fieldKey]` first, then falls back
 * to `locale.fieldTitles[fieldKey]`, and finally to the raw key itself.
 *
 * @example
 * getFieldTitle(locales.en, "book",  "author")  // → "Author(s)"
 * getFieldTitle(locales.en, "video", "author")  // → "Director(s)"
 * getFieldTitle(locales.de, "book",  "author")  // → "Autor(en)"
 */
export function getFieldTitle(
    locale: Locale,
    typeKey: string,
    fieldKey: string,
): string {
    return (
        locale.fieldTitlesByType[typeKey]?.[fieldKey] ??
        locale.fieldTitles[fieldKey] ??
        fieldKey
    )
}

/**
 * Return the human-readable label for *typeKey* in *locale*, falling back to
 * the raw key if not found.
 *
 * @example
 * getTypeTitle(locales.fr, "article-journal")  // → "Article de revue"
 */
export function getTypeTitle(locale: Locale, typeKey: string): string {
    return locale.typeTitles[typeKey] ?? typeKey
}

/**
 * Return the help/hint text for *fieldKey* in *locale*, or `undefined` when
 * no help text is defined for that field.
 *
 * @example
 * getFieldHelp(locales.en, "date")   // → "In <em>Extended Date Time Format</em>…"
 * getFieldHelp(locales.en, "title")  // → undefined
 */
export function getFieldHelp(
    locale: Locale,
    fieldKey: string,
): string | undefined {
    return locale.fieldHelp[fieldKey]
}

/**
 * Return the human-readable label for a `langid` field value in *locale*,
 * falling back to the raw key if not found.
 *
 * @example
 * getLangidTitle(locales.de, "french")       // → "Französisch"
 * getLangidTitle(locales.en, "brportuguese") // → "Brazilian Portuguese"
 */
export function getLangidTitle(locale: Locale, langidKey: string): string {
    return locale.langidOptions[langidKey] ?? langidKey
}

/**
 * Return the human-readable label for a non-language option value in *locale*
 * (i.e. an `editortype`, `pagination`, `pubstate`, or `type` sub-field value),
 * falling back to the raw key if not found.
 *
 * @example
 * getOtherOptionTitle(locales.de, "phdthesis")     // → "Ph.D. These"
 * getOtherOptionTitle(locales.en, "inpreparation") // → "In preparation"
 */
export function getOtherOptionTitle(locale: Locale, optionKey: string): string {
    return locale.otherOptions[optionKey] ?? optionKey
}
