"""Baseline rule-based sin LLM. Genera results/raw/rule-baseline.jsonl compatible con metrics.py."""
import json
import re
from datetime import date, timedelta
from pathlib import Path

REPO = Path(__file__).resolve().parent.parent
DS = json.loads((REPO / "data" / "dataset.json").read_text(encoding="utf-8"))
BASE = date.fromisoformat(DS["base_date"])
OUT = REPO / "results" / "raw" / "rule-baseline.jsonl"

AMOUNT_RE = re.compile(r"\$?\s?(\d{1,3}(?:[.,]\d{3})+|\d[\d.,]*)\s*(palos?|lucas|mil|k)?", re.I)
MULT = {"lucas": 1000, "mil": 1000, "k": 1000, "palo": 1_000_000, "palos": 1_000_000}

def _norm(s):
    s = s.lower()
    for a, b in [("á","a"),("é","e"),("í","i"),("ó","o"),("ú","u"),("ü","u")]:
        s = s.replace(a, b)
    return s

ING_RAW = ["cobré","cobre","cobrado","me pagaron","me llego plata","me llegó plata","transferencia","recibí","recibi","devolvieron","venta","depositaron","sobró","sobro"]
EGR_RAW = ["gasté","gaste","pagué","pague","pagamos","compré","compre","me dejé","me deje","se me fue","aboné","abone","débito","debito","saqué","saque","pago"]
ING_KWS = {_norm(x) for x in ING_RAW}
EGR_KWS = {_norm(x) for x in EGR_RAW}
# ponytail: taxonomia cerrada default de LUKA
TAXONOMY = {"comida":"Comida","supermercado":"Comida","super":"Comida","nafta":"Transporte","transporte":"Transporte","taxi":"Transporte","luz":"Servicios","gas":"Servicios","internet":"Servicios","cable":"Servicios","wifi":"Servicios","alquiler":"Vivienda","farmacia":"Salud","ropa":"Ropa","sueldo":"Ingresos","trabajo":"Ingresos","venta":"Ingresos","ocio":"Ocio"}
DAY_WD = {"lunes":0,"martes":1,"miercoles":2,"jueves":3,"viernes":4,"sabado":5,"domingo":6}

def parse_amount(text):
    m = AMOUNT_RE.search(text)
    if not m:
        return None
    raw, suf = m.group(1), m.group(2)
    # ponytail: tolerar $5.000 con punto miles -> quitar separadores
    num = raw.replace(".", "").replace(",", "")
    try:
        v = float(num)
    except Exception:
        return None
    if suf:
        v *= MULT.get(suf.lower(), 1)
    return float(v)

def parse_type(text):
    low = _norm(text)
    ing = any(k in low for k in ING_KWS)
    egr = any(k in low for k in EGR_KWS)
    # ponytail: ambos tipos en single -> ambiguo -> None
    if ing and egr:
        return None
    if ing:
        return "ingreso"
    if egr:
        return "egreso"
    return None

def parse_date(text, base):
    low = _norm(text)
    if "ayer" in low:
        return (base - timedelta(days=1)).isoformat()
    # ponytail: último día estrictamente anterior
    for name, wd in DAY_WD.items():
        if name in low:
            delta = (base.weekday() - wd) % 7
            if delta == 0:
                delta = 7
            return (base - timedelta(days=delta)).isoformat()
    return None

def parse_category(text):
    low = _norm(text)
    for k, v in TAXONOMY.items():
        if k in low:
            return v
    return None

def parse_multi(text, base):
    low = _norm(text)
    amts = list(AMOUNT_RE.finditer(text))
    if " y " not in low or len(amts) < 2:
        # ponytail: también " e "
        if " e " not in low or len(amts) < 2:
            return None
        clauses = re.split(r"\s+e\s+", text, flags=re.I)
    else:
        clauses = re.split(r"\s+y\s+", text, flags=re.I)
    if len(clauses) < 2:
        return None
    fecha = parse_date(text, base)
    movs = []
    for cl in clauses:
        amt = parse_amount(cl)
        typ = parse_type(cl)
        if amt is None or typ is None:
            return None
        cat = parse_category(cl)
        desc = f"gasto en {cat.lower()}" if typ=="egreso" and cat else f"cobro de {cat.lower()}" if typ=="ingreso" and cat else None
        movs.append({"movement_type": typ, "amount": float(amt), "currency": "ARS", "category": cat, "description": desc, "reply_text": "Estoy procesando el movimiento.", "fecha": fecha})
    return movs if len(movs) >= 2 else None

def build_llm(text, base):
    movs = parse_multi(text, base)
    if movs is not None:
        # ponytail: movimientos multiop ya válidos
        first = movs[0]
        llm = {"intent": "expense", "movement_type": first["movement_type"], "amount": first["amount"], "currency": first["currency"], "category": first["category"], "description": first["description"], "reply_text": "Estoy procesando el movimiento.", "fecha": first["fecha"], "movements": []}
        for m in movs:
            llm["movements"].append({"intent": "expense", "movement_type": m["movement_type"], "amount": m["amount"], "currency": m["currency"], "category": m["category"], "description": m["description"], "reply_text": m["reply_text"], "fecha": m["fecha"]})
        # completar campos conocidos con None para schema
        for k in ["expense","limit_amount","limit_category","limit_month","limit_year","reminder_amount","reminder_concept","reminder_currency","reminder_date","reminder_day","reminder_id","reminder_title"]:
            llm.setdefault(k, None)
        return llm
    amt = parse_amount(text)
    typ = parse_type(text)
    cat = parse_category(text)
    fecha = parse_date(text, base)
    if typ == "egreso" and cat:
        desc = f"gasto en {cat.lower()}"
    elif typ == "ingreso" and cat:
        desc = f"cobro de {cat.lower()}"
    else:
        desc = None
    if amt is None or typ is None:
        if amt is None:
            reply = "Necesito que me indiques el monto para registrar el movimiento."
        else:
            reply = "Necesito que aclares si es ingreso o egreso."
    else:
        reply = "Estoy procesando el movimiento."
    currency = "ARS" if (amt is not None or typ is not None) else None
    # ponytail: currency ARS default
    mov = {"intent": "expense", "movement_type": typ, "amount": float(amt) if amt is not None else None, "currency": currency, "category": cat, "description": desc, "reply_text": reply, "fecha": fecha}
    llm = {"intent": "expense", "movement_type": typ, "amount": float(amt) if amt is not None else None, "currency": currency, "category": cat, "description": desc, "reply_text": reply, "fecha": fecha, "movements": [mov]}
    for k in ["expense","limit_amount","limit_category","limit_month","limit_year","reminder_amount","reminder_concept","reminder_currency","reminder_date","reminder_day","reminder_id","reminder_title"]:
        llm.setdefault(k, None)
    return llm

def main():
    OUT.parent.mkdir(parents=True, exist_ok=True)
    n = 0
    with open(OUT, "w", encoding="utf-8") as f:
        for msg in DS["messages"]:
            llm = build_llm(msg["text"], BASE)
            rec = {"id": msg["id"], "type": msg["type"], "text": msg["text"], "provider": "rule", "model": "rule-baseline", "latency_ms": 0, "ok": True, "llm": llm}
            f.write(json.dumps(rec, ensure_ascii=False) + "\n")
            n += 1
    # self-check
    cnt = sum(1 for m in DS["messages"] if m["type"] in ("simple","coloquial","temporal") and parse_amount(m["text"]) is not None)
    # ponytail: 75/84 umbral mínimo de cobertura de montos
    assert cnt >= 75, f"self-check falló: solo {cnt}/84 montos detectados en simple/coloquial/temporal"
    print(f"rule-baseline ok: {n} registros -> {OUT} ; montos detectados simple/coloq/temp {cnt}/84")

if __name__ == "__main__":
    main()
