"""Motor de Tramitación LME invocado por PHP.

Uso:
    python tramitacion_engine.py --datos <regs.json> --modo prueba|envio --job <id>

`regs.json` (preparado por PHP) es una lista de registros, cada uno:
  { folio, rut, nombre, entidad_pagadora, contrato,
    liquidaciones: { "YYYY-MM": {dias, imponible, pdf}, ... }, avisos: [...] }

Escribe avance/resultados en estado/<job>.json. En PRUEBA no presiona 'Tramitar'.
"""
import argparse
import json
import os
import time
import traceback
from datetime import datetime

from tramitacion import TramitacionBot, TramitacionError

ESTADO_DIR = "estado"
LIQ_DIR = "liquidaciones"


def _extraer_pagina(masivo, pagina, salida):
    """Extrae una página del PDF masivo a un PDF individual (para adjuntar)."""
    from pypdf import PdfReader, PdfWriter
    reader = PdfReader(masivo)
    idx = int(pagina) - 1
    if idx < 0 or idx >= len(reader.pages):
        raise ValueError(f"página {pagina} fuera de rango en {os.path.basename(masivo)}")
    w = PdfWriter()
    w.add_page(reader.pages[idx])
    with open(salida, "wb") as f:
        w.write(f)


def _preparar_pdfs(reg, job_dir):
    """Genera los PDF de cada mes (desde masivo+pagina) y setea 'pdf' en el mapa."""
    os.makedirs(job_dir, exist_ok=True)
    for clave, d in (reg.get("liquidaciones") or {}).items():
        masivo = os.path.join(LIQ_DIR, os.path.basename(d.get("masivo", "")))
        if not d.get("masivo") or not os.path.isfile(masivo):
            raise TramitacionError(f"Falta el PDF masivo de {clave} (RUT {reg.get('rut')}).")
        nombre = f"Liquidacion_{reg.get('rut','')}_{clave}.pdf".replace(" ", "_")
        salida = os.path.join(job_dir, nombre)
        _extraer_pagina(masivo, d.get("pagina"), salida)
        d["pdf"] = os.path.abspath(salida)


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--datos", required=True)
    ap.add_argument("--modo", choices=["prueba", "envio"], default="prueba")
    ap.add_argument("--job", required=True)
    args = ap.parse_args()

    os.makedirs(ESTADO_DIR, exist_ok=True)
    ruta_estado = os.path.join(ESTADO_DIR, f"{args.job}.json")
    enviar = args.modo == "envio"

    estado = {
        "corriendo": True, "terminado": False, "modo": args.modo,
        "total": 0, "progreso": 0, "paso": "Iniciando...",
        "log": [], "resultados": [],
        "inicio": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
    }

    def guardar():
        tmp = ruta_estado + ".tmp"
        try:
            with open(tmp, "w", encoding="utf-8") as f:
                json.dump(estado, f, ensure_ascii=False)
        except Exception:
            return
        for _ in range(20):
            try:
                os.replace(tmp, ruta_estado); return
            except PermissionError:
                time.sleep(0.1)
            except Exception:
                break
        try:
            with open(ruta_estado, "w", encoding="utf-8") as f:
                json.dump(estado, f, ensure_ascii=False)
            if os.path.exists(tmp):
                os.remove(tmp)
        except Exception:
            pass

    def log(msg):
        estado["log"].append(f"[{datetime.now():%H:%M:%S}] {msg}")
        guardar()

    guardar()
    try:
        with open(args.datos, encoding="utf-8") as f:
            regs = json.load(f)
        total = len(regs) or 1
        estado["total"] = len(regs)
        log(f"{len(regs)} tramitación(es). Modo: "
            f"{'ENVÍO REAL' if enviar else 'PRUEBA (no tramita)'}")

        with TramitacionBot(headless=True) as bot:
            estado["paso"] = "Iniciando sesión en el portal LME..."; guardar()
            log("Iniciando sesión en el portal LME...")
            bot.login()
            log("Sesión iniciada.")

            for i, reg in enumerate(regs):
                fila = reg.get("_fila_excel")
                folio = reg.get("folio")
                if reg.get("avisos"):
                    coment = "ERROR: " + " · ".join(reg["avisos"])
                    estado["resultados"].append({
                        "fila": fila, "folio": folio, "rut": reg.get("rut"),
                        "estado": "ERROR", "comentario": coment, "error": coment})
                    log(f"Fila {fila}: {coment}")
                    estado["progreso"] = int((i + 1) / total * 100); guardar()
                    continue

                if i > 0:
                    # Pequeño respiro entre folios: encadenar acciones sin pausa
                    # sobrecarga al portal y aumenta la chance de spinners que no
                    # bajan a tiempo o botones que quedan momentáneamente bloqueados.
                    time.sleep(3)

                log(f"Fila {fila} · Folio {folio} · RUT {reg.get('rut')} — procesando...")

                def cb(frac, texto, _i=i, _fila=fila):
                    estado["progreso"] = min(100, int((_i + frac) / total * 100))
                    estado["paso"] = f"Tramitación {_i + 1}/{total} (fila {_fila}): {texto}"
                    guardar()

                try:
                    _preparar_pdfs(reg, os.path.join(ESTADO_DIR, f"tram_{args.job}_pdfs"))
                    r = bot.procesar_folio(reg, enviar=enviar, prog=cb)
                    r["fila"] = fila
                    r["rut"] = reg.get("rut")
                    r["entidad"] = reg.get("entidad_pagadora")
                    r["contrato"] = reg.get("contrato")
                    r["excel_origen"] = reg.get("excel_origen", "")
                    r.setdefault("estado", "OK")
                    r.setdefault("comentario", r.get("modo", ""))
                    estado["resultados"].append(r)
                    estado["progreso"] = int((i + 1) / total * 100)
                    log(f"Fila {fila}: {r.get('comentario')} — {r.get('nombre','')}")
                except (TramitacionError, Exception) as e:
                    estado["resultados"].append({
                        "fila": fila, "folio": folio, "rut": reg.get("rut"),
                        "estado": "ERROR", "comentario": f"ERROR: {e}", "error": str(e)})
                    log(f"Fila {fila}: ERROR — {e}")
                    estado["progreso"] = int((i + 1) / total * 100); guardar()
        estado["progreso"] = 100
        estado["paso"] = "Proceso finalizado."
        log("Proceso finalizado.")
    except Exception as e:
        estado["paso"] = f"Error: {e}"
        log(f"FALLO GENERAL: {e}")
        log(traceback.format_exc())
    finally:
        estado["corriendo"] = False
        estado["terminado"] = True
        guardar()


if __name__ == "__main__":
    main()
