"""Stratigrafia lexicului românesc: definiția straturilor și maparea lor pe
categoriile Wiktionary.

Un strat = un canal istoric prin care cuvintele au intrat în română. Regula de
atribuire este *donatorul proxim*: cine a dat cuvântul româna direct, nu de unde
venea cuvântul înainte. „Dragoste" e slavonă, deși slavona îl luase din
protoslavă; „bulevard" e franceză, deși franceza îl luase din olandeză.

Ordinea din PRIORITY decide când un cuvânt apare în mai multe categorii.
"""

# id, cod ISO-ish al donatorului, categoriile Wiktionary care îl populează
STRATA = [
    dict(
        id="substrat",
        window=(-1000, 100),
        cats=[
            "Romanian terms derived from substrate languages",
            "Romanian terms borrowed from Albanian",
            "Romanian terms derived from Albanian",
            "Romanian terms inherited from Albanian",
        ],
    ),
    dict(
        id="latina",
        window=(106, 700),
        cats=[
            "Romanian terms inherited from Latin",
            "Romanian terms inherited from Vulgar Latin",
            "Romanian terms inherited from Late Latin",
            "Romanian terms inherited from Proto-Romance",
        ],
    ),
    dict(
        id="slava",
        window=(600, 1000),
        cats=[
            "Romanian terms inherited from Proto-Slavic",
            "Romanian terms borrowed from Proto-Slavic",
            "Romanian terms derived from Proto-Slavic",
        ],
    ),
    dict(
        id="slavona",
        window=(1000, 1700),
        cats=[
            "Romanian terms borrowed from Old Church Slavonic",
            "Romanian terms borrowed from Church Slavonic",
            "Romanian terms derived from Old Church Slavonic",
        ],
    ),
    dict(
        id="maghiara",
        window=(1100, 1900),
        cats=[
            "Romanian terms borrowed from Hungarian",
            "Romanian terms borrowed from Old Hungarian",
        ],
    ),
    dict(
        id="greaca",
        window=(1000, 1830),
        cats=[
            "Romanian terms borrowed from Byzantine Greek",
            "Romanian terms borrowed from Greek",
            "Romanian terms borrowed from Ancient Greek",
            "Romanian terms borrowed from Koine Greek",
            "Romanian terms borrowed from Medieval Greek",
        ],
    ),
    dict(
        id="turca",
        window=(1400, 1880),
        cats=[
            "Romanian terms borrowed from Ottoman Turkish",
            "Romanian terms borrowed from Turkish",
            "Romanian terms borrowed from Crimean Tatar",
            "Romanian terms borrowed from Cuman",
            "Romanian terms borrowed from Pecheneg",
        ],
    ),
    dict(
        id="vecini",
        window=(1500, 1950),
        cats=[
            "Romanian terms borrowed from Bulgarian",
            "Romanian terms borrowed from Serbo-Croatian",
            "Romanian terms borrowed from Ukrainian",
            "Romanian terms borrowed from Russian",
            "Romanian terms borrowed from Polish",
            "Romanian terms borrowed from Slovak",
            "Romanian terms borrowed from Czech",
        ],
    ),
    dict(
        id="germana",
        window=(1200, 1950),
        cats=[
            "Romanian terms borrowed from German",
            "Romanian terms borrowed from Middle High German",
            "Romanian terms borrowed from Bavarian",
            "Romanian terms borrowed from Austrian German",
            "Romanian terms borrowed from Yiddish",
        ],
    ),
    dict(
        id="latina_savanta",
        window=(1780, 1900),
        cats=[
            "Romanian terms borrowed from Latin",
            "Romanian terms borrowed from New Latin",
            "Romanian terms borrowed from Late Latin",
            "Romanian terms borrowed from Medieval Latin",
        ],
    ),
    dict(
        id="italiana",
        window=(1800, 1930),
        cats=[
            "Romanian terms borrowed from Italian",
            "Romanian terms borrowed from Venetian",
        ],
    ),
    dict(
        id="franceza",
        window=(1830, 1918),
        cats=[
            "Romanian terms borrowed from French",
            "Romanian terms borrowed from Middle French",
            "Romanian terms borrowed from Old French",
        ],
    ),
    dict(
        id="engleza",
        window=(1960, 2026),
        cats=[
            "Romanian terms borrowed from English",
            "Romanian terms borrowed from American English",
        ],
    ),
    dict(
        id="interna",
        window=(1500, 2026),
        cats=[
            "Romanian compound terms",
            "Romanian terms suffixed with -ime",
        ],
    ),
    dict(
        id="necunoscut",
        window=(None, None),
        cats=[
            "Romanian terms with unknown etymologies",
            "Romanian terms with uncertain etymologies",
            "Romanian onomatopoeias",
        ],
    ),
]

# Donatorul proxim câștigă. Straturile „interna" și „necunoscut" se aplică numai
# dacă nimic altceva nu s-a potrivit, fiindcă Wiktionary pune un compus și în
# categoria rădăcinii lui.
PRIORITY = [
    "substrat",
    "turca",
    "slavona",
    "slava",
    "maghiara",
    "greaca",
    "vecini",
    "germana",
    "engleza",
    "franceza",
    "italiana",
    "latina_savanta",
    "latina",
    "interna",
    "necunoscut",
]

# Codurile de limbă din șabloanele {{inh|ro|X}} / {{bor|ro|X}}, pentru cazurile
# în care citim direct wikitextul și nu apartenența la categorie.
CODE_TO_STRATUM = {
    "qfa-sub": "substrat", "sq": "substrat", "aln": "substrat",
    "la": "latina", "la-vul": "latina", "la-lat": "latina", "la-pro": "latina",
    "sla-pro": "slava", "sla": "slava",
    "cu": "slavona", "chu": "slavona",
    "hu": "maghiara", "ohu": "maghiara",
    "gkm": "greaca", "el": "greaca", "grc": "greaca", "grc-koi": "greaca",
    "ota": "turca", "tr": "turca", "crh": "turca", "qwm": "turca",
    "bg": "vecini", "sh": "vecini", "uk": "vecini", "ru": "vecini",
    "pl": "vecini", "sk": "vecini", "cs": "vecini", "sr": "vecini",
    "de": "germana", "gmh": "germana", "bar": "germana", "yi": "germana",
    "it": "italiana", "vec": "italiana",
    "fr": "franceza", "frm": "franceza", "fro": "franceza",
    "en": "engleza",
    "la-new": "latina_savanta", "la-med": "latina_savanta", "la-eme": "latina_savanta",
    "la-cla": "latina_savanta",
}

STRATUM_IDS = [s["id"] for s in STRATA]
ALL_CATS = [(s["id"], c) for s in STRATA for c in s["cats"]]


def load_overrides():
    """Corecțiile verificate de mână, din tools/overrides.json."""
    import json, os
    p = os.path.join(os.path.dirname(os.path.abspath(__file__)), "overrides.json")
    if not os.path.exists(p):
        return {}
    with open(p, encoding="utf8") as f:
        d = json.load(f)
    return {k: v for k, v in d.items() if not k.startswith("_")}


def load_dex_ety():
    """Verdictul dexonline pe cuvânt, cu cât de sigur e."""
    import json, os
    p = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                     "..", "raw", "dex_ety.json")
    if not os.path.exists(p):
        return {}
    with open(p, encoding="utf8") as f:
        d = json.load(f)
    # formatul vechi ținea doar stratul
    return {k: (v if isinstance(v, dict) else {"layer": v, "votes": 1, "total": 1})
            for k, v in d.items()}


# Un verdict dexonline se ia în locul celui de la Wiktionary dacă îl susțin cel
# puțin două definiții și cel puțin două treimi dintre cele care spun ceva.
DEX_MIN_VOTES = 2
DEX_MIN_SHARE = 2 / 3

# Reconcilierea se aplică numai la donatorii pe care abrevierea românească îi
# numește fără echivoc. „Din lat." acoperă și cuvântul moștenit în secolul al
# treilea și împrumutul savant din secolul al nouăsprezecelea, iar „sl." acoperă
# slavona, protoslava și bulgara; acolo nota nu poate decide, așa că nu decide.
# Substratul și etimologia necunoscută rămân și ele neatinse: dezacordul dintre
# ele e chiar lucrul pe care pagina îl arată.
DEX_UNAMBIGUOUS = {
    "franceza", "turca", "maghiara", "greaca", "germana", "italiana",
    "engleza", "vecini",
}


def proximate_layers(categories, reconcile=True):
    """lexem → stratul donatorului proxim.

    Categoriile se aplică de la prioritate mică la mare, ca donatorul cel mai
    apropiat să scrie ultimul: un cuvânt franțuzesc care vine din latină apare
    în ambele categorii, iar cel care l-a dat românei e franceza.

    Pe urmă intervine dexonline. Wiktionary ține un singur articol pentru
    omonimele cu istorii diferite, iar noi citim prima secțiune de etimologie,
    care nu e întotdeauna cea a sensului obișnuit: „corp" ajunge german, „stat"
    ajunge italian. Dicționarele românești adunate de dexonline sunt a doua
    părere, iar când mai multe dintre ele spun același lucru, ea câștigă.
    """
    lay = {}
    for st in reversed(PRIORITY):
        for words in categories.get(st, {}).values():
            for w in words:
                lay[w] = st
    if reconcile:
        for w, d in load_dex_ety().items():
            if w not in lay or d["layer"] == lay[w]:
                continue
            if d["layer"] not in DEX_UNAMBIGUOUS:
                continue
            if d["votes"] >= DEX_MIN_VOTES and d["votes"] / d["total"] >= DEX_MIN_SHARE:
                lay[w] = d["layer"]
    # corecțiile de mână bat orice
    for w, o in load_overrides().items():
        if w in lay:
            lay[w] = o["layer"]
    return lay
