"""Motor de automatización invocado por la capa PHP.

Uso:
    python engine.py --excel <ruta.xlsx> --modo prueba|envio --job <id> [--fila N]

Escribe el avance y los resultados en:  estado/<job>.json
(la capa PHP lo consulta para mostrar el progreso y luego lo guarda en MySQL).
"""
import argparse
import json
import os
import sys
import time
import traceback
from datetime import datetime

from excel_reader import leer_licencias
from automation import LicenciaBot, LicenciaError
from remuneraciones import escribir_en_excel, escribir_comentario

ESTADO_DIR = "estado"


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--excel", required=True)
    ap.add_argument("--modo", choices=["prueba", "envio"], default="prueba")
    ap.add_argument("--job", required=True)
    ap.add_argument("--fila", type=int, default=None)
    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": [], "excel": args.excel,
        "inicio": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
    }

    def guardar():
        # Escribe a un temporal y renombra. En Windows el renombrado puede fallar
        # (WinError 5) si PHP está leyendo el .json justo en ese instante: se reintenta.
        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
        # Último recurso: escribir directo (PHP tolera lecturas parciales)
        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:
        licencias = leer_licencias(args.excel)
        if args.fila:
            licencias = [l for l in licencias if l.get("_fila_excel") == args.fila]
        total = len(licencias) or 1
        estado["total"] = len(licencias)
        log(f"{len(licencias)} licencia(s) a procesar. Modo: "
            f"{'ENVÍO REAL' if enviar else 'PRUEBA (no guarda)'}")

        with LicenciaBot(headless=True) as bot:
            estado["paso"] = "Iniciando sesión..."; guardar()
            log("Iniciando sesión en el sistema...")
            bot.login()
            log("Sesión iniciada correctamente.")

            for i, lic in enumerate(licencias):
                fila = lic.get("_fila_excel")
                log(f"Fila {fila} · RUT {lic['rut']} · Lic {lic['num_licencia']} — procesando...")

                def cb(frac, texto, _i=i, _fila=fila):
                    estado["progreso"] = min(100, int((_i + frac) / total * 100))
                    estado["paso"] = f"Licencia {_i + 1}/{total} (fila {_fila}): {texto}"
                    guardar()

                try:
                    r = bot.ingresar_licencia(lic, enviar=enviar, on_progress=cb)
                    remun = r.get("remuneraciones")
                    if enviar and r.get("pdf_cobro_sil") and remun and remun.get("meses"):
                        try:
                            escribir_en_excel(args.excel, r["fila_excel"], remun,
                                              os.path.basename(r["pdf_cobro_sil"]))
                        except Exception as e:
                            log(f"Fila {fila}: no pude escribir remuneraciones: {e}")

                    if not enviar:
                        coment = "Prueba OK (campos válidos, no guardada)"
                    elif r.get("pdf_cobro_sil"):
                        coment = "Guardada · Cobro SIL OK"
                    elif r.get("enviado"):
                        coment = f"Guardada (sin Cobro SIL: {r.get('error_cobro_sil','')})"
                    else:
                        coment = "Revisar: no se confirmó el guardado"
                    if r.get("aviso_previo"):
                        coment += f" · Aviso: {r['aviso_previo']}"
                        log(f"Fila {fila}: aviso del sistema antes de grabar: {r['aviso_previo']}")
                    if r.get("aviso_prenatal"):
                        coment += " · Pre/Post Natal: se acortaron días (se continuó)"
                        log(f"Fila {fila}: aviso Pre/Post Natal (se continuó): {r['aviso_prenatal']}")
                    _comentar(args.excel, fila, coment, log)

                    estado["resultados"].append({
                        "fila": fila, "rut": r.get("rut"),
                        "nombre": r.get("nombre_cargado"),
                        "num_licencia": r.get("num_licencia"),
                        "fecha_emision": lic.get("fecha_emision"),
                        "estado": "OK", "modo": r.get("modo"),
                        "pdf": os.path.basename(r["pdf_cobro_sil"]) if r.get("pdf_cobro_sil") else "",
                        "remuneraciones": remun,
                        "comentario": coment,
                        "excel_origen": os.path.basename(args.excel),
                    })
                    estado["progreso"] = int((i + 1) / total * 100)
                    log(f"Fila {fila}: OK — {r.get('nombre_cargado')}")
                    if r.get("pdf_cobro_sil"):
                        log(f"Fila {fila}: Cobro SIL -> {r['pdf_cobro_sil']}")
                except LicenciaError as e:
                    _comentar(args.excel, fila, f"ERROR: {e}", log)
                    estado["resultados"].append({
                        "fila": fila, "rut": lic["rut"], "estado": "ERROR",
                        "comentario": f"ERROR: {e}", "error": str(e)})
                    log(f"Fila {fila}: ERROR — {e}")
                except Exception as e:
                    _comentar(args.excel, fila, f"ERROR: {e}", log)
                    estado["resultados"].append({
                        "fila": fila, "rut": lic["rut"], "estado": "ERROR",
                        "comentario": f"ERROR: {e}", "error": str(e)})
                    log(f"Fila {fila}: ERROR inesperado — {e}")
        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()


def _comentar(excel, fila, texto, log):
    try:
        escribir_comentario(excel, fila, texto)
    except Exception as e:
        log(f"Fila {fila}: no pude escribir comentario: {e}")


if __name__ == "__main__":
    main()
