"""Verifică atribuirea straturilor cu o a doua sursă, independentă de Wiktionary.

Fiecare definiție din dexonline își încheie textul cu o notă etimologică: „– Din
fr. boulevard.", „– Lat. casa.", „– Din tc. çorba.". Extragem prima limbă numită
în notă, o traducem în stratul nostru și măsurăm de câte ori cele două surse
spun același lucru. Dezacordurile se scriu într-un fișier, ca să se poată citi.

Ieșiri: raw/dex_ety.json, content/data/agreement.json
"""
import gzip, json, os, re, sys
from collections import Counter, defaultdict

HERE = os.path.dirname(os.path.abspath(__file__))
RAW = os.path.join(HERE, "..", "raw")
DATA = os.path.join(HERE, "..", "content", "data")
sys.path.insert(0, HERE)
from strata import PRIORITY, proximate_layers
from dex_extract import tuples

# Abrevierile de limbă folosite în notele etimologice din dicționarele românești.
ABBR = {
    "lat": "latina", "ltg": "latina",
    "fr": "franceza", "franc": "franceza",
    "tc": "turca", "turc": "turca", "tăt": "turca", "tat": "turca", "cum": "turca",
    "sl": "slavona", "slv": "slavona", "vsl": "slavona", "slav": "slavona",
    "magh": "maghiara", "ung": "maghiara",
    "ngr": "greaca", "gr": "greaca", "mgr": "greaca", "bgr": "greaca",
    "germ": "germana", "germ.med": "germana", "săs": "germana", "sas": "germana",
    "austr": "germana", "idiș": "germana",
    "it": "italiana", "ven": "italiana",
    "engl": "engleza", "eng": "engleza", "amer": "engleza",
    "rus": "vecini", "bg": "vecini", "ucr": "vecini", "srb": "vecini",
    "scr": "vecini", "pol": "vecini", "ceh": "vecini", "rut": "vecini",
    "alb": "substrat",
    "ebr": None, "ar": None, "pers": None, "sanscr": None, "sp": None,
}
# Notele care spun explicit că e formare internă sau necunoscut.
INTERNAL_RE = re.compile(r"\b(?:din|cf\.?)\s+(?:rom|rom\.)\b|\bformați[ei]\b", re.I)
UNKNOWN_RE = re.compile(r"et(?:imologie)?\.?\s*(?:nec|necunoscută|nesigură|obscură)", re.I)

ETY_RE = re.compile(
    r"(?:—|–|-|–)\s*(?:Din\s+|Cf\.?\s+|După\s+)?"
    r"((?:[a-zăâîșț]{2,7}\.?\s*){1,3})",
)
LANG_TOKEN = re.compile(r"\b([a-zăâîșț]{2,7})\.")


def strip_markup(s):
    s = re.sub(r"@|\$|#|\*|\|", "", s)
    s = re.sub(r"\{[^}]*\}", " ", s)
    return re.sub(r"\s+", " ", s).strip()


def dex_layer(rep):
    """Stratul pe care îl declară nota etimologică, dacă îl declară."""
    txt = strip_markup(rep)
    tail = txt[-260:]
    if UNKNOWN_RE.search(tail):
        return "necunoscut"
    m = re.search(r"(?:—|–|-)\s*(?:Din|Cf\.?|După)?\s*([^.]{0,60}\.)", tail)
    window = tail[m.start():] if m else tail
    for tok in LANG_TOKEN.findall(window):
        if tok in ABBR:
            return ABBR[tok]
    for tok in LANG_TOKEN.findall(tail):
        if tok in ABBR:
            return ABBR[tok]
    return None


def main():
    shortlist = set(json.load(open(os.path.join(RAW, "shortlist.json"), encoding="utf8")))
    cats = json.load(open(os.path.join(RAW, "categories.json"), encoding="utf8"))
    lay = proximate_layers(cats, reconcile=False)

    found = defaultdict(list)
    pat = re.compile(r"^INSERT INTO `Definition` VALUES ")
    print("citesc definițiile din dumpul dexonline...")
    with gzip.open(os.path.join(RAW, "dex-database.sql.gz"), "rt",
                   encoding="utf8", errors="replace") as fh:
        for line in fh:
            if not pat.match(line):
                continue
            for r in tuples(line):
                if len(r) < 5:
                    continue
                head = r[3]
                if head not in shortlist:
                    continue
                st = dex_layer(r[4])
                if st:
                    found[head].append(st)
    print(f"cuvinte cu notă etimologică în dexonline: {len(found)}")

    # Acordul se măsoară la două niveluri. Strict: același strat. Larg: aceeași
    # limbă-sursă, indiferent de drum. Notele românești scriu „din lat." și
    # pentru cuvântul moștenit, și pentru împrumutul savant de secol XIX, iar
    # slava veche, protoslava și bulgara se confundă în abrevierea „sl.".
    FAMILY = {
        "latina": "latin", "latina_savanta": "latin",
        "slava": "slav", "slavona": "slav", "vecini": "slav",
    }
    fam = lambda s: FAMILY.get(s, s)

    agree = disagree = fam_agree = 0
    pairs = Counter()
    examples = defaultdict(list)
    dex_pick = {}
    for w, votes in found.items():
        c = Counter(votes)
        best, n = c.most_common(1)[0]
        # Păstrăm și cât de sigură e nota: câte dicționare o spun și cât de mare
        # e majoritatea. Reconcilierea de mai târziu se uită la asta.
        dex_pick[w] = {"layer": best, "votes": n, "total": len(votes)}
        mine = lay.get(w)
        if not mine:
            continue
        best_layer = best
        if fam(mine) == fam(best_layer):
            fam_agree += 1
        if mine == best_layer:
            agree += 1
        else:
            disagree += 1
            pairs[(mine, best_layer)] += 1
            if len(examples[(mine, best_layer)]) < 12:
                examples[(mine, best_layer)].append(w)

    tot = agree + disagree
    print(f"\ncomparabile: {tot}   acord strict: {agree} ({agree/tot*100:.1f}%)   "
          f"acord pe limba-sursă: {fam_agree} ({fam_agree/tot*100:.1f}%)")
    print("\ncele mai frecvente dezacorduri (wiktionary → dexonline):")
    for (a, b), n in pairs.most_common(14):
        print(f"  {n:>5}  {a:<15} → {b:<15} {', '.join(examples[(a,b)][:6])}")

    with open(os.path.join(RAW, "dex_ety.json"), "w", encoding="utf8") as f:
        json.dump(dex_pick, f, ensure_ascii=False)
    os.makedirs(DATA, exist_ok=True)
    with open(os.path.join(DATA, "agreement.json"), "w", encoding="utf8") as f:
        json.dump({
            "compared": tot, "agree": agree, "disagree": disagree,
            "rate": round(agree / tot, 4) if tot else None,
            "family_agree": fam_agree,
            "family_rate": round(fam_agree / tot, 4) if tot else None,
            "with_dex_note": len(found),
            "pairs": [{"wikt": a, "dex": b, "n": n, "examples": examples[(a, b)]}
                      for (a, b), n in pairs.most_common(30)],
        }, f, ensure_ascii=False, indent=1)
    print("\nscris raw/dex_ety.json și content/data/agreement.json")


if __name__ == "__main__":
    main()
