"""Normalizacja tekstu używana wszędzie w pipeline'ie matchingu.

Cel: dwie formy tej samej nazwy (różne casing, akcenty, interpunkcja, whitespace, „the"/myślniki)
muszą produkować identyczny string po `normalize`. Trgram index na tych polach robi resztę.
"""
from __future__ import annotations

import re
import unicodedata

from slugify import slugify as _slugify

_NON_ASCII_ALNUM_RE = re.compile(r"[^a-z0-9\s]+")
_WS_RE = re.compile(r"\s+")
_LEADING_ARTICLE_RE = re.compile(r"^(the|a|an)\s+", flags=re.IGNORECASE)

# Litery których NFKD nie rozkłada na ASCII — mapujemy ręcznie.
_EXTRA_TRANSLIT = str.maketrans(
    {
        "Ł": "L", "ł": "l",
        "Ø": "O", "ø": "o",
        "Æ": "AE", "æ": "ae",
        "Œ": "OE", "œ": "oe",
        "Þ": "Th", "þ": "th",
        "Ð": "D", "ð": "d",
        "Đ": "D", "đ": "d",
        "ß": "ss",
        "Ħ": "H", "ħ": "h",
    }
)


def strip_accents(value: str) -> str:
    pre = value.translate(_EXTRA_TRANSLIT)
    nfkd = unicodedata.normalize("NFKD", pre)
    return "".join(c for c in nfkd if not unicodedata.combining(c))


def normalize(value: str | None) -> str:
    """Lower + strip accents + remove punctuation + collapse whitespace + drop leading article."""
    if not value:
        return ""
    out = strip_accents(value).lower()
    out = _NON_ASCII_ALNUM_RE.sub(" ", out)
    out = _WS_RE.sub(" ", out).strip()
    out = _LEADING_ARTICLE_RE.sub("", out)
    return out


def normalize_person(value: str | None) -> str:
    """Normalizacja imion: jak `normalize`, plus zwija inicjały „M." → „m"."""
    if not value:
        return ""
    out = normalize(value)
    return _WS_RE.sub(" ", out).strip()


def slugify(value: str | None) -> str:
    if not value:
        return ""
    return _slugify(value, lowercase=True, max_length=200)
