#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Auditoría READ-ONLY del Verificador (Baserow tabla 750) y la Mesa de control
(tabla 749) contra la lista OFICIAL de cuentas (n8n/cuentas_oficiales.csv).

El workflow n8n [2004] resuelve la sucursal encadenando:
    webhook location.name -> 749.Nombre (7235) -> 750."SC BUCEFALO" (7247)
Para que el match funcione, AMBOS (749.Nombre y 750.SC BUCEFALO) deben ser
idénticos al nombre oficial de la cuenta (lo que GHL manda en location.name).

Fuente de verdad:
  - Nombre canónico: `n8n/cuentas_oficiales.csv` (name <-> location_id).
  - SUCURSAL / TIENDA: Verificador CSV local (load_verifier_map), donde exista.

Reporta (cruce por location_id, excluye Marca y DEMO):
  - fix_749            : 749.Nombre != oficial            (rompe el 1er match)
  - mismatch_750       : 750."SC BUCEFALO" != oficial      (rompe el 2do match)
  - sucursal_vacia / tienda_vacia : con subclase csv_tiene (automatizable) o sin_fuente (Erandi)
  - ausente_750        : oficial sin fila en 750
  - sin_749            : oficial sin fila en 749
  - filas_no_oficiales : filas de 750 cuyo location_id no está en la lista oficial (no se tocan)

Uso:
    python scripts/audit_baserow_verificador.py
"""

import csv
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 fill_sucursal_tienda_from_location import load_verifier_map  # noqa: E402

TABLE_CUENTAS = 749
TABLE_VERIFICADOR = 750
BRAND_LOCATION_ID = "GbKkBpCmKu2QmloKFHy3"
OFICIAL_CSV = os.path.join(ROOT_DIR, "n8n", "cuentas_oficiales.csv")

F_749_NOMBRE = "Nombre"
F_749_LOC = "Location_ID"
F_SC_BUCEFALO = "SC BUCEFALO"
F_SUCURSAL = "SUCURSAL"
F_TIENDA = "TIENDA"
F_ID_LOC = "ID LOCATION BUCEFALO"


def clean(v):
    return str(v or "").strip()


def load_official_accounts(path=None):
    """{location_id: name} de la lista oficial; excluye Marca y cuentas DEMO."""
    path = path or OFICIAL_CSV
    out = {}
    with open(path, encoding="utf-8-sig", newline="") as fh:
        for r in csv.DictReader(fh):
            loc = clean(r.get("location_id"))
            name = clean(r.get("name"))
            if not loc or loc == BRAND_LOCATION_ID or "demo" in name.lower():
                continue
            out[loc] = name
    return out


def audit(client=None, oficial=None, verifier_map=None):
    """Devuelve el dict de discrepancias. Reutilizable por el corrector."""
    client = client or BaserowClient.from_credentials()
    oficial = oficial if oficial is not None else load_official_accounts()
    verifier_map = verifier_map if verifier_map is not None else load_verifier_map()

    rows749 = client.list_rows(TABLE_CUENTAS)
    rows750 = client.list_rows(TABLE_VERIFICADOR)
    n749 = {clean(r.get(F_749_LOC)): r for r in rows749 if clean(r.get(F_749_LOC))}
    n750 = {clean(r.get(F_ID_LOC)): r for r in rows750 if clean(r.get(F_ID_LOC))}

    res = {
        "totals": {"oficiales": len(oficial), "filas_749": len(rows749), "filas_750": len(rows750)},
        "fix_749": [], "mismatch_750": [], "sucursal_vacia": [], "tienda_vacia": [],
        "ausente_750": [], "sin_749": [], "filas_no_oficiales": [],
    }

    for loc, name in oficial.items():
        row749 = n749.get(loc)
        if not row749:
            res["sin_749"].append({"location_id": loc, "oficial": name})
        elif clean(row749.get(F_749_NOMBRE)) != name:
            res["fix_749"].append({"location_id": loc, "row_id": row749.get("id"),
                                   "actual": clean(row749.get(F_749_NOMBRE)), "oficial": name})

        row750 = n750.get(loc)
        csv_entry = verifier_map.get(loc) or {}
        csv_suc = clean(csv_entry.get("sucursal"))
        csv_tie = clean(csv_entry.get("tienda"))
        if not row750:
            res["ausente_750"].append({"location_id": loc, "oficial": name,
                                       "csv_sucursal": csv_suc, "csv_tienda": csv_tie})
            continue
        if clean(row750.get(F_SC_BUCEFALO)) != name:
            res["mismatch_750"].append({"location_id": loc, "row_id": row750.get("id"),
                                        "actual": clean(row750.get(F_SC_BUCEFALO)), "oficial": name})
        if not clean(row750.get(F_SUCURSAL)):
            res["sucursal_vacia"].append({"location_id": loc, "row_id": row750.get("id"), "oficial": name,
                                          "csv_sucursal": csv_suc,
                                          "fuente": "csv_tiene" if csv_suc else "sin_fuente"})
        if not clean(row750.get(F_TIENDA)):
            res["tienda_vacia"].append({"location_id": loc, "row_id": row750.get("id"), "oficial": name,
                                        "csv_tienda": csv_tie,
                                        "fuente": "csv_tiene" if csv_tie else "sin_fuente"})

    for loc, row in n750.items():
        if loc != BRAND_LOCATION_ID and loc not in oficial:
            res["filas_no_oficiales"].append({"location_id": loc, "row_id": row.get("id"),
                                              "sc_bucefalo": clean(row.get(F_SC_BUCEFALO))})
    return res


def _sec(title, items, fmt):
    print(f"\n=== {title}: {len(items)} ===")
    for it in items:
        print("  " + fmt(it))


def main():
    if hasattr(sys.stdout, "reconfigure"):
        sys.stdout.reconfigure(encoding="utf-8")
    res = audit()
    print("=" * 72)
    print("AUDITORÍA BASEROW (749 + 750) vs lista OFICIAL de cuentas")
    print("=" * 72)
    t = res["totals"]
    print(f"Oficiales={t['oficiales']} | filas 749={t['filas_749']} | filas 750={t['filas_750']}")
    _sec("749.Nombre != oficial (corregir 749) [rompe 1er match]", res["fix_749"],
         lambda x: f"{x['actual']!r} -> {x['oficial']!r}  [{x['location_id']}]")
    _sec("750.SC_BUCEFALO != oficial (corregir 750) [rompe 2do match]", res["mismatch_750"],
         lambda x: f"{x['actual']!r} -> {x['oficial']!r}  (row {x['row_id']})")
    _sec("SUCURSAL vacía", res["sucursal_vacia"],
         lambda x: f"{x['oficial']!r} fuente={x['fuente']} csv={x['csv_sucursal']!r}")
    _sec("TIENDA vacía", res["tienda_vacia"],
         lambda x: f"{x['oficial']!r} fuente={x['fuente']} csv={x['csv_tienda']!r}")
    _sec("Oficiales ausentes en 750 (crear)", res["ausente_750"],
         lambda x: f"{x['oficial']!r} csv_suc={x['csv_sucursal']!r} csv_tie={x['csv_tienda']!r}  [{x['location_id']}]")
    _sec("Oficiales sin fila en 749", res["sin_749"], lambda x: f"{x['oficial']!r}  [{x['location_id']}]")
    _sec("Filas 750 NO oficiales (se ignoran)", res["filas_no_oficiales"],
         lambda x: f"{x['sc_bucefalo']!r}  [{x['location_id']}]")

    os.makedirs(REPORTS_DIR, exist_ok=True)
    out = os.path.join(REPORTS_DIR, "audit_baserow_verificador.json")
    with open(out, "w", encoding="utf-8") as fh:
        json.dump(res, fh, ensure_ascii=False, indent=2)
    print(f"\nReporte JSON -> {out}")


if __name__ == "__main__":
    main()
