#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Corrector automático de Baserow (Mesa de control 749 + Verificador 750) para
que el workflow n8n [2004] deje de fallar.

Base / fuente de verdad:
  - Nombre de match (749.Nombre y 750."SC BUCEFALO")  <- `n8n/cuentas_oficiales.csv`
  - SUCURSAL / TIENDA                                   <- Verificador CSV local (load_verifier_map),
                                                           solo donde el CSV tenga dato y 750 esté vacío.
Lo que no tiene fuente (solo lo conoce Erandi) NO se inventa: se entrega en
generated/reports/baserow_pendientes_erandi.json.

Acciones (idempotentes; la auditoría solo reporta lo que difiere):
  - PATCH 749.Nombre        = oficial   (arregla el 1er match)
  - PATCH 750."SC BUCEFALO"  = oficial   (arregla el 2do match)
  - PATCH 750.SUCURSAL/TIENDA desde el CSV (donde el CSV los tenga)
  - POST  fila nueva en 750 para oficiales ausentes
Las filas de 750 cuyo location_id NO es oficial NO se tocan.

Uso:
    python scripts/fix_baserow_verificador.py            # DRY-RUN (no escribe)
    python scripts/fix_baserow_verificador.py --apply     # aplica (backup previo de 749 y 750)
"""

import argparse
import json
import os
import sys

ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if ROOT_DIR not in sys.path:
    sys.path.insert(0, ROOT_DIR)

from paths import REPORTS_DIR  # noqa: E402
from baserow_client import BaserowClient  # noqa: E402
from audit_baserow_verificador import (  # noqa: E402
    audit, TABLE_CUENTAS, TABLE_VERIFICADOR,
    F_749_NOMBRE, F_SC_BUCEFALO, F_SUCURSAL, F_TIENDA, F_ID_LOC,
)

ERANDI_REPORT = os.path.join(REPORTS_DIR, "baserow_pendientes_erandi.json")


def build_plan(res):
    """Acciones automatizables (updates 749/750, creates) + lista para Erandi."""
    updates = []   # {table, row_id, fields, motivo}
    creates = []   # {table, fields, motivo}
    erandi = {}    # location_id -> {nombre, falta:set}

    def need(loc, nombre, col):
        erandi.setdefault(loc, {"location_id": loc, "nombre": nombre, "falta": set()})["falta"].add(col)

    for f in res["fix_749"]:
        updates.append({"table": TABLE_CUENTAS, "row_id": f["row_id"], "fields": {F_749_NOMBRE: f["oficial"]},
                        "motivo": f"749.Nombre {f['actual']!r} -> {f['oficial']!r}"})
    for m in res["mismatch_750"]:
        updates.append({"table": TABLE_VERIFICADOR, "row_id": m["row_id"], "fields": {F_SC_BUCEFALO: m["oficial"]},
                        "motivo": f"750.SC_BUCEFALO {m['actual']!r} -> {m['oficial']!r}"})
    for s in res["sucursal_vacia"]:
        if s["fuente"] == "csv_tiene":
            updates.append({"table": TABLE_VERIFICADOR, "row_id": s["row_id"], "fields": {F_SUCURSAL: s["csv_sucursal"]},
                            "motivo": f"SUCURSAL vacío -> {s['csv_sucursal']!r} (CSV)"})
        else:
            need(s["location_id"], s["oficial"], "SUCURSAL")
    for t in res["tienda_vacia"]:
        if t["fuente"] == "csv_tiene":
            updates.append({"table": TABLE_VERIFICADOR, "row_id": t["row_id"], "fields": {F_TIENDA: t["csv_tienda"]},
                            "motivo": f"TIENDA vacío -> {t['csv_tienda']!r} (CSV)"})
        else:
            need(t["location_id"], t["oficial"], "TIENDA")
    for a in res["ausente_750"]:
        fields = {F_ID_LOC: a["location_id"], F_SC_BUCEFALO: a["oficial"]}
        if a["csv_sucursal"]:
            fields[F_SUCURSAL] = a["csv_sucursal"]
        if a["csv_tienda"]:
            fields[F_TIENDA] = a["csv_tienda"]
        creates.append({"table": TABLE_VERIFICADOR, "fields": fields, "motivo": f"crear fila para {a['oficial']!r}"})
        for col, val in [("SUCURSAL", a["csv_sucursal"]), ("TIENDA", a["csv_tienda"])]:
            if not val:
                need(a["location_id"], a["oficial"], col)

    erandi_final = [{"location_id": k, "nombre": v["nombre"], "falta": sorted(v["falta"])}
                    for k, v in erandi.items()]
    return updates, creates, erandi_final


def main():
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")
    parser = argparse.ArgumentParser(description="Corrige Baserow 749/750 desde la lista oficial + CSV. Dry-run por defecto.")
    parser.add_argument("--apply", action="store_true", help="Aplica los cambios en Baserow. Sin esto: dry-run.")
    args = parser.parse_args()
    dry_run = not args.apply

    client = BaserowClient.from_credentials()
    res = audit(client=client)
    updates, creates, erandi = build_plan(res)
    u749 = [u for u in updates if u["table"] == TABLE_CUENTAS]
    u750 = [u for u in updates if u["table"] == TABLE_VERIFICADOR]

    print("=" * 72)
    print("CORRECTOR BASEROW (749 Mesa de control + 750 Verificador)")
    print("=" * 72)
    print(f"Modo: {'DRY-RUN (no escribe)' if dry_run else 'APPLY (escribe en Baserow)'}")
    print(f"PATCH 749: {len(u749)} | PATCH 750: {len(u750)} | POST nuevas: {len(creates)} | pendientes Erandi: {len(erandi)}")
    print("\n--- PATCH tabla 749 (Mesa de control) ---")
    for u in u749:
        print(f"  row {u['row_id']}: {u['motivo']}")
    print("\n--- PATCH tabla 750 (Verificador) ---")
    for u in u750:
        print(f"  row {u['row_id']}: {u['motivo']}")
    print("\n--- POST tabla 750 (crear ausentes) ---")
    for c in creates:
        print(f"  {c['motivo']}: {c['fields']}")
    print("\n--- PENDIENTES ERANDI (sin fuente; NO se inventan) ---")
    for e in erandi:
        print(f"  {e['nombre']!r} falta: {e['falta']}  [{e['location_id']}]")

    os.makedirs(REPORTS_DIR, exist_ok=True)
    with open(ERANDI_REPORT, "w", encoding="utf-8") as fh:
        json.dump(erandi, fh, ensure_ascii=False, indent=2)
    print(f"\nLista para Erandi -> {ERANDI_REPORT}")

    if dry_run:
        print("\nDry-run terminado. Revisa el plan y vuelve a correr con --apply para aplicar.")
        return
    if not updates and not creates:
        print("\nNada que aplicar (Baserow ya está alineado).")
        return

    b749 = client.backup_table(TABLE_CUENTAS, label="mesa_control_fix")
    b750 = client.backup_table(TABLE_VERIFICADOR, label="verificador_fix")
    print(f"\nBackups -> {b749}\n          {b750}")
    ok = err = 0
    for u in updates:
        try:
            client.update_row(u["table"], u["row_id"], u["fields"], dry_run=False)
            ok += 1
            print(f"  OK PATCH t{u['table']} row {u['row_id']}: {u['motivo']}")
        except Exception as exc:
            err += 1
            print(f"  ERROR PATCH t{u['table']} row {u['row_id']}: {exc}")
    for c in creates:
        try:
            client.create_row(c["table"], c["fields"], dry_run=False)
            ok += 1
            print(f"  OK POST t{c['table']}: {c['motivo']}")
        except Exception as exc:
            err += 1
            print(f"  ERROR POST t{c['table']} {c['motivo']}: {exc}")
    print(f"\nAplicado: {ok} acciones, {err} errores.")
    if err:
        raise SystemExit(1)


if __name__ == "__main__":
    main()
