#!/usr/bin/env python3
"""
Las notas del presupuesto pasan a ser CLIENTE-FACING (se muestran en el PDF y al
copiar el detalle). Históricamente el código de cortes se guardaba en `notas`,
así que hay que moverlo al campo `calculo` (interno) antes de mostrarlas.

Qué hace, por presupuesto:
  1. Si `notas` parece código de cortes y `calculo` está VACÍO → calculo = notas,
     notas = "". (Sin pérdida: el código no se borra, cambia de campo.)
  2. Si `notas` es ruido interno ("Creado desde Pedido rápido.") → notas = "".
  3. Cualquier otra nota (texto real para el cliente) NO se toca.

Es idempotente: una vez migrado, `notas` ya no matchea y no vuelve a tocarse.
Guarda un backup JSON de la colección antes de escribir.

Uso (desde el server):
  PB_URL=http://localhost:8102 PB_ADMIN_EMAIL=... PB_ADMIN_PASSWORD=... \
    python3 backend/scripts/migrate_notas_a_calculo.py          # dry-run
    python3 backend/scripts/migrate_notas_a_calculo.py --apply  # escribe
"""
import json
import os
import re
import sys
from datetime import datetime

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from create_collections import auth_admin, req  # noqa: E402

# Marcas del código de la calculadora: tags (#Mueble, #Corte, …) o separadores.
CORTES_RE = re.compile(r"#(Corte|Mueble|Estandar|Medida|Caj|Pino|Herraje)|^-{3,}", re.M)
RUIDO = {"creado desde pedido rápido.", "creado desde pedido rapido."}


def main() -> int:
    apply = "--apply" in sys.argv
    base = os.environ.get("PB_URL", "http://localhost:8102")
    token = auth_admin()

    code, res = req("GET", "/api/collections/presupuestos/records?perPage=500&fields=id,codigo,notas,calculo",
                    token=token)
    if code != 200:
        print(f"FATAL: no se pudieron leer los presupuestos: {code} {res}", file=sys.stderr)
        return 1
    items = res.get("items", [])

    stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
    backup = f"/tmp/presupuestos-notas-backup-{stamp}.json"
    with open(backup, "w", encoding="utf-8") as fh:
        json.dump(items, fh, ensure_ascii=False, indent=1)
    print(f"Backup de {len(items)} presupuestos → {backup}")

    mover, limpiar, conflicto = [], [], []
    for it in items:
        notas = (it.get("notas") or "").strip()
        calculo = (it.get("calculo") or "").strip()
        if not notas:
            continue
        if notas.lower() in RUIDO:
            limpiar.append(it)
        elif CORTES_RE.search(notas):
            (mover if not calculo else conflicto).append(it)

    print(f"\n  mover notas → calculo : {len(mover)}")
    print(f"  limpiar ruido         : {len(limpiar)}")
    print(f"  con calculo ya cargado (SE SALTEAN, revisar a mano): {len(conflicto)}")
    for it in conflicto:
        print(f"    ! {it.get('codigo')}")

    if not apply:
        print("\nDRY-RUN. Nada se escribió. Correr con --apply para aplicar.")
        return 0

    fallos = 0
    for it in mover:
        code, data = req("PATCH", f"/api/collections/presupuestos/records/{it['id']}",
                         token=token, body={"calculo": it.get("notas") or "", "notas": ""})
        if code != 200:
            fallos += 1
            print(f"  ERROR moviendo {it.get('codigo')}: {code} {data}", file=sys.stderr)
    for it in limpiar:
        code, data = req("PATCH", f"/api/collections/presupuestos/records/{it['id']}",
                         token=token, body={"notas": ""})
        if code != 200:
            fallos += 1
            print(f"  ERROR limpiando {it.get('codigo')}: {code} {data}", file=sys.stderr)

    print(f"\nOK ({base}): {len(mover)} movidos, {len(limpiar)} limpiados, {fallos} fallos.")
    print(f"Si algo salió mal, el backup está en {backup}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
