"""Gettext bindings and explicit process-locale setup."""

import gettext
import locale
import os
import sys
from pathlib import Path

_DOMAIN = "bigocrpdf"


def _(text: str) -> str:
    return gettext.dgettext(_DOMAIN, text)


def ngettext(singular: str, plural: str, count: int) -> str:
    return gettext.dngettext(_DOMAIN, singular, plural, count)


def _locale_dir_candidates() -> list[Path]:
    """Locale directories to probe, most specific first.

    Ordering matters for relocatable builds: an AppImage carries its own
    catalogs under ``$APPDIR/usr/share/locale`` and must never fall through to
    the host ``/usr/share/locale``, which may hold a stale catalog from a
    system-wide install or none at all.
    """
    candidates: list[Path] = []

    override = os.environ.get("BIGOCRPDF_LOCALE_DIR")
    if override:
        candidates.append(Path(override))

    appdir = os.environ.get("APPDIR")
    if appdir:
        candidates.append(Path(appdir) / "usr/share/locale")

    # The AppRun generated by appimage-creator exports this.
    textdomaindir = os.environ.get("TEXTDOMAINDIR")
    if textdomaindir:
        candidates.append(Path(textdomaindir))

    # Walking up from this module covers every layout the package can be
    # installed in -- source checkout, wheel under site-packages, AppDir --
    # without needing to know the prefix in advance.
    for parent in Path(__file__).resolve().parents:
        candidates.append(parent / "share/locale")
        candidates.append(parent / "usr/share/locale")

    candidates.extend((Path(sys.prefix) / "share/locale", Path("/usr/share/locale")))
    return candidates


def _find_locale_dir() -> Path:
    for candidate in _locale_dir_candidates():
        if any(candidate.glob(f"*/LC_MESSAGES/{_DOMAIN}.mo")):
            return candidate
    return Path("/usr/share/locale")


def N_(text: str) -> str:
    """Mark a string for extraction without translating it at definition time.

    Use this for strings that are defined as constants but translated later
    via ``_()``.  Extraction tools (xgettext / pybabel) will pick up the
    string, but it is returned unchanged so the runtime ``_()`` call can
    do the actual translation.
    """
    return text


def setup_i18n() -> None:
    """Configure locale and bind the application gettext domain once."""
    try:
        locale.setlocale(locale.LC_ALL, "")
        locale.setlocale(locale.LC_NUMERIC, "C")
    except locale.Error:
        locale.setlocale(locale.LC_ALL, "C")
    locale_dir = str(_find_locale_dir())
    gettext.bindtextdomain(_DOMAIN, locale_dir)
    gettext.textdomain(_DOMAIN)

    # Bind on the C library as well so translations still apply to strings
    # resolved outside Python's gettext -- GtkBuilder templates and anything
    # GLib translates on our behalf.  Absent on non-glibc platforms.
    try:
        locale.bindtextdomain(_DOMAIN, locale_dir)  # type: ignore[attr-defined]
        locale.textdomain(_DOMAIN)  # type: ignore[attr-defined]
    except AttributeError:
        pass
