#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Corrector Verificador (Baserow 750): clasificación TIPO DE TIENDA + colapso
de filas digitales ambiguas a 1 fila canónica por location digital.

Modelo (confirmado con datos en vivo 2026-05-30):
  - Zona Toluca/Metepec/Lerma -> hub digital PILARES (85935), TIENDA=PILARES, FULL AUTOS.
  - Morelia -> MORELIA 1 (85964), FULL AUTOS.
  - Tiendas NO DIGITAL (0 contactos en vivo): 85937/85938/85939/85940/85941/85965.
  - Las filas NO DIGITAL huérfanas se dejan SIN SUCURSAL a propósito (no colisionan).

Reversible: hace backup_table() antes de cualquier escritura. Dry-run por defecto.

Uso:
    python scripts/fix_baserow_tipo_de_tienda.py            # dry-run (default)
    python scripts/fix_baserow_tipo_de_tienda.py --apply --only routing   # piloto routing
    python scripts/fix_baserow_tipo_de_tienda.py --apply --only labels    # batch TIPO=PARCIAL
    python scripts/fix_baserow_tipo_de_tienda.py --apply                   # todo
"""
import argparse
import os
import sys

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

from scripts.baserow_client import BaserowClient  # noqa: E402

TABLE = 750
SUC, TIE, SC, LOC, TIPO = "SUCURSAL", "TIENDA", "SC BUCEFALO", "ID LOCATION BUCEFALO", "TIPO DE TIENDA"

# Ops ROUTING-críticas: (row_id, expectativa_actual {col:val}, accion)
#   accion = ("update", {col:val})  |  ("delete",)
ROUTING_OPS = [
    # Toluca: colapsar 3 -> 1 canónica + borrar 2 redundantes
    (241, {SUC: "Toluca", TIE: "GRAND PLAZA", SC: "85935"}, ("update", {TIE: "PILARES", TIPO: "FULL AUTOS"})),
    (242, {SUC: "Toluca", TIE: "ISIDRO FABELA", SC: "85935"}, ("delete",)),
    (243, {SUC: "Toluca", TIE: "INDEPENDENCIA", SC: "85935"}, ("delete",)),
    # Lerma: fila digital canónica
    (244, {SUC: "Lerma", TIE: "SENDERO", SC: "85935"}, ("update", {TIE: "PILARES", TIPO: "FULL AUTOS"})),
    # Metepec: dedup (240 y 254 idénticas NO DIGITAL -> borrar 254)
    (254, {SUC: "Metepec", TIE: "METEPEC", SC: "85937"}, ("delete",)),
    # Junk
    (258, {TIPO: "TIPO DE TIENDA"}, ("delete",)),
]

# Rows que deben quedar PARCIAL (single-store digitales con TIPO vacío).
# Se identifican por TIPO vacío y SUCURSAL no vacía y no en el set FULL AUTOS/ya clasificado.
FULL_AUTOS_KEEP = {211, 213, 220, 229, 233, 234, 251}  # ya FULL AUTOS en vivo


def norm(s):
    return (s or "").strip().lower()


def matches(row, expect):
    for col, val in expect.items():
        cur = norm(row.get(col))
        if norm(val) not in cur:
            return False, f"col {col!r}: live={row.get(col)!r} no contiene {val!r}"
    return True, ""


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--apply", action="store_true", help="aplica (default dry-run)")
    ap.add_argument("--only", choices=["routing", "labels"], help="limita el alcance")
    args = ap.parse_args()
    dry = not args.apply

    c = BaserowClient.from_credentials()
    rows = {r["id"]: r for r in c.list_rows(TABLE)}
    print(f"Baserow 750: {len(rows)} filas. Modo={'DRY-RUN' if dry else 'APPLY'} only={args.only or 'todo'}")

    if not dry:
        path = c.backup_table(TABLE, label="verificador_pre_tipo_tienda")
        print(f"  backup -> {path}")

    planned, errors = [], []

    # --- ROUTING ---
    if args.only in (None, "routing"):
        for rid, expect, action in ROUTING_OPS:
            row = rows.get(rid)
            if not row:
                errors.append(f"[routing] fila {rid} no existe")
                continue
            ok, why = matches(row, expect)
            if not ok:
                errors.append(f"[routing] fila {rid} mismatch: {why}")
                continue
            planned.append(("routing", rid, row, action))

    # --- LABELS (TIPO=PARCIAL en vacíos) ---
    if args.only in (None, "labels"):
        routing_ids = {rid for rid, _, _ in ROUTING_OPS}
        for rid, row in rows.items():
            if rid in routing_ids or rid in FULL_AUTOS_KEEP:
                continue
            suc, tipo = norm(row.get(SUC)), norm(row.get(TIPO))
            if not suc or suc == "-":
                continue  # cuenta principal / huérfanas sin SUCURSAL -> no tocar
            if tipo in ("", "·"):
                planned.append(("labels", rid, row, ("update", {TIPO: "PARCIAL"})))

    if errors:
        print("\nABORTA — mismatches (datos cambiaron desde el dump):")
        for e in errors:
            print("  " + e)
        if not dry:
            sys.exit(1)

    print(f"\nOperaciones planeadas: {len(planned)}")
    for cat, rid, row, action in planned:
        label = f"[{cat}] fila {rid} ({row.get(SUC)!r}/{row.get(TIE)!r}/{row.get(SC)!r})"
        if action[0] == "update":
            print(f"  UPDATE {label} -> {action[1]}")
            c.update_row(TABLE, rid, action[1], dry_run=dry)
        elif action[0] == "delete":
            print(f"  DELETE {label}")
            c.delete_row(TABLE, rid, dry_run=dry)

    print("\nOK" + (" (dry-run, sin cambios)" if dry else " (aplicado)"))


if __name__ == "__main__":
    main()
