"""Corectie etichete SILVER: inlocuirea de anvelope -> OE-8.

Seed-ul Haiku a etichetat sistematic "INLOCUIT ANVELOPE ..." cu OE-1 (REPARATIE),
desi nomenclatorul RAR are un cod dedicat: OE-8 (INLOCUIRE SEZONIERA A ANVELOPELOR).
Eroarea domina vecinatatea k-NN (223 OE-1 vs 17 OE-8), asa ca votul sugera OE-1
pentru orice "Inlocuire anvelope".

Regula (deterministica, aceeasi in DB si in seed):
  text NORMALIZAT care contine un verb de inlocuire/montare
  (INLOCUIT/INLOCUIRE/INL/SCHIMB*/MONTAT/MONTARE) SI anvelope la plural
  (ANVELOPE/CAUCIUCURI), FARA context de reparatie (JANTA, D/R, D/M, REPARAT,
  VULCANIZ, PRESIUNE, DEPRESAT) -> OE-8.
  Singularul cu pozitie ("INLOCUIT ANVELOPA DR FATA") ramane OE-1: e tipic
  inlocuire dupa pana/uzura in cadrul unei reparatii, nu schimb sezonier.

In plus, adauga intrari canonice OE-8 curate manual (`CURATE_OE8`) pentru
formularile uzuale de schimb sezonier absente din corpus ("MONTAT CAUCIUCURI
VARA" etc.) — fara ele, k-NN nu are niciun vecin relevant si votul cade pe
zgomot de coada.

Aplica idempotent pe:
  - tabela `mapping_suggestions` (sursa corpusului k-NN la runtime)
  - `app/data/operatii-etichetate.json` (seed-ul pentru instalari noi)
`source` devine "haiku_seed+fix_oe8" pe randurile corectate, "curat_manual"
pe cele adaugate (audit).

Rulare:
    python3 tools/mapare-llm/fix_anvelope_oe8.py --db data/autopass.db [--dry-run]
"""
from __future__ import annotations

import argparse
import json
import os
import re
import sqlite3

_HERE = os.path.dirname(os.path.abspath(__file__))
_ROOT = os.path.abspath(os.path.join(_HERE, "..", ".."))
SEED_PATH = os.path.join(_ROOT, "app", "data", "operatii-etichetate.json")

VERB = re.compile(r"\b(INLOCUIT|INLOCUIRE|INL|SCHIMB|SCHIMBAT|SCHIMBARE|MONTAT|MONTARE)\b")
PLURAL = re.compile(r"ANVELOPE|CAUCIUCURI")
EXCLUDERE = re.compile(r"JANTA|D/R|D/M|REPARAT|VULCANIZ|PRESIUNE|DEPRESAT")

# Formulari canonice de schimb sezonier, absente din corpusul Haiku.
# Texte deja in forma normalizata (majuscule ASCII, fara diacritice).
CURATE_OE8 = [
    "INLOCUIRE ANVELOPE",
    "SCHIMBARE ANVELOPE",
    "SCHIMB ANVELOPE",
    "SCHIMBAT ANVELOPE IARNA",
    "SCHIMBAT ANVELOPE VARA",
    "MONTAT ANVELOPE IARNA",
    "MONTAT ANVELOPE VARA",
    "MONTAT CAUCIUCURI IARNA",
    "MONTAT CAUCIUCURI VARA",
    "SCHIMB CAUCIUCURI",
    "SCHIMBAT ROTI IARNA",
    "SCHIMBAT ROTI VARA",
    "INLOCUIRE SEZONIERA ANVELOPE",
]


def este_inlocuire_anvelope(text_normalizat: str) -> bool:
    """True daca textul descrie o inlocuire/montare de anvelope (plural)."""
    t = text_normalizat or ""
    return bool(VERB.search(t) and PLURAL.search(t) and not EXCLUDERE.search(t))


def fix_db(conn: sqlite3.Connection, dry_run: bool) -> int:
    rows = conn.execute(
        "SELECT id, denumire_normalizata FROM mapping_suggestions "
        "WHERE is_nul=0 AND cod_prestatie != 'OE-8' "
        "AND (denumire_normalizata LIKE '%ANVELOP%' OR denumire_normalizata LIKE '%CAUCIUC%')"
    ).fetchall()
    ids = [r[0] for r in rows if este_inlocuire_anvelope(r[1])]
    if not dry_run and ids:
        conn.executemany(
            "UPDATE mapping_suggestions SET cod_prestatie='OE-8', "
            "source='haiku_seed+fix_oe8', updated_at=datetime('now') WHERE id=?",
            [(i,) for i in ids],
        )
        conn.commit()
    return len(ids)


def adauga_curate_db(conn: sqlite3.Connection, dry_run: bool) -> int:
    n = 0
    for t in CURATE_OE8:
        exists = conn.execute(
            "SELECT 1 FROM mapping_suggestions WHERE denumire_normalizata=?", (t,)
        ).fetchone()
        if exists:
            continue
        n += 1
        if not dry_run:
            conn.execute(
                "INSERT INTO mapping_suggestions "
                "(denumire_normalizata, cod_prestatie, is_nul, source, confidence) "
                "VALUES (?, 'OE-8', 0, 'curat_manual', 1.0)",
                (t,),
            )
    if not dry_run:
        conn.commit()
    return n


def adauga_curate_seed(items: list[dict], dry_run: bool) -> int:
    existente = {it.get("denumire_normalizata") for it in items}
    n = 0
    for t in CURATE_OE8:
        if t in existente:
            continue
        n += 1
        if not dry_run:
            items.append({
                "denumire": t,
                "denumire_normalizata": t,
                "cod": "OE-8",
                "is_nul": False,
                "source": "curat_manual",
                "confidence": 1.0,
            })
    return n


def fix_seed(dry_run: bool) -> tuple[int, int]:
    with open(SEED_PATH, encoding="utf-8") as f:
        items = json.load(f)
    n = 0
    for it in items:
        if it.get("is_nul") or it.get("cod") == "OE-8":
            continue
        if este_inlocuire_anvelope(it.get("denumire_normalizata") or ""):
            it["cod"] = "OE-8"
            it["source"] = "haiku_seed+fix_oe8"
            n += 1
    n_curate = adauga_curate_seed(items, dry_run)
    if not dry_run and (n or n_curate):
        with open(SEED_PATH, "w", encoding="utf-8") as f:
            # acelasi format ca genereaza_seed.py (diff git minimal la corectii)
            json.dump(items, f, ensure_ascii=False, indent=2)
    return n, n_curate


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("--db", default=os.path.join(_ROOT, "data", "autopass.db"))
    ap.add_argument("--dry-run", action="store_true")
    args = ap.parse_args()

    conn = sqlite3.connect(args.db)
    n_db = fix_db(conn, args.dry_run)
    n_db_curate = adauga_curate_db(conn, args.dry_run)
    n_seed, n_seed_curate = fix_seed(args.dry_run)
    eticheta = "(dry-run) " if args.dry_run else ""
    print(
        f"{eticheta}DB: {n_db} relabel + {n_db_curate} curate; "
        f"seed JSON: {n_seed} relabel + {n_seed_curate} curate"
    )


if __name__ == "__main__":
    main()
