"""Automatización de 'Recuperación de Licencia Médica' (SIRH La Pintana).

Flujo por fila del Excel:
  Consulta -> buscar por RUT -> seleccionar por N° licencia ->
  leer valores del sitio -> completar Detalle del Pago -> Grabar Detalle.

Reutiliza el login y utilidades de LicenciaBot (automation.py).
"""
import os
import re
from playwright.sync_api import TimeoutError as PWTimeout
from config import SEL_REC, REC_URL, normaliza, rut_valido, limpiar_num_licencia
from automation import LicenciaBot, LicenciaError, CAPTURAS_DIR


def _rut_busqueda(rut):
    """RUT canónico para el buscador: sin puntos, sin espacios y SIN ceros a la
    izquierda (el sitio no matchea '09829369-8'; sí '9829369-8')."""
    s = str(rut or "").upper().replace(".", "").replace(" ", "")
    if "-" in s:
        cuerpo, _, dv = s.partition("-")
    else:
        cuerpo, dv = s[:-1], s[-1:]
    cuerpo = cuerpo.lstrip("0") or "0"
    return f"{cuerpo}-{dv}"


class RecuperacionBot(LicenciaBot):
    def abrir(self):
        """Tras login, abre la página de Recuperación de Licencia Médica."""
        self.page.goto(REC_URL, wait_until="domcontentloaded", timeout=45000)
        self.page.wait_for_timeout(2000)

    # ---- lectura segura ----
    def _val(self, sel):
        try:
            return (self.page.input_value(sel) or "").strip()
        except Exception:
            return ""

    def _fill_si(self, sel, valor):
        """Llena el campo solo si viene un valor (deja el default del sitio si no)."""
        if valor is None or str(valor).strip() == "":
            return
        self.page.fill(sel, str(valor).strip())

    def _grid_vacio(self):
        """True si el buscador no devolvió funcionario (muestra 'Sin Datos' o no hay
        filas con fecha de licencia)."""
        filas = self.page.eval_on_selector_all(
            f"{SEL_REC['grilla']} tr", "els=>els.map(r=>(r.innerText||'').trim())")
        texto = " ".join(filas).lower()
        if "sin datos" in texto:
            return True
        return not any(re.search(r"\d{2}/\d{2}/\d{4}", f) for f in filas)

    def _click_fila(self, num_lic):
        """Si la página actual de la grilla contiene la licencia, hace click en su
        botón Seleccionar y devuelve True."""
        pg = self.page
        fila = pg.locator(f"{SEL_REC['grilla']} tr", has_text=str(num_lic)).first
        if fila.count():
            fila.locator("input[type=image], a").first.click()
            return True
        return False

    def _ordenar_fecha_desc(self):
        """Ordena la grilla por F. Licencia descendente (lo más nuevo primero).
        Best-effort: si falla, el recorrido completo igual encuentra la licencia."""
        pg = self.page

        def click_sort():
            for a in pg.query_selector_all(f"{SEL_REC['grilla']} a"):
                try:
                    h = a.get_attribute("href") or ""
                except Exception:
                    continue
                if "Sort$FECHA_LICENCIA" in h:
                    a.click()
                    pg.wait_for_timeout(1400)
                    try:
                        pg.wait_for_load_state("networkidle", timeout=6000)
                    except PWTimeout:
                        pass
                    return True
            return False

        def anio_primera():
            filas = pg.eval_on_selector_all(
                f"{SEL_REC['grilla']} tr",
                "els=>els.map(r=>(r.innerText||'').trim()).filter(t=>/\\b\\d{2}-\\d{2}-\\d{4}\\b/.test(t))")
            for t in filas:
                m = re.search(r"\b\d{2}-\d{2}-(\d{4})\b", t)
                if m:
                    return int(m.group(1))
            return None

        if not click_sort():
            return
        anio = anio_primera()
        # Si quedó ascendente (arriba una licencia antigua), voltear a descendente
        if anio is not None and anio < 2024:
            click_sort()

    def _seleccionar_licencia(self, num_lic):
        """Busca la licencia recorriendo TODAS las páginas del pager de la grilla.
        Lee el número de página real desde el href (Page$N) de cada link, así cruza
        los '...' de un paginador con ventana (1 2 3 ... 10 ...)."""
        pg = self.page
        visitadas = set()
        for _ in range(300):  # tope alto: funcionarios con muchas licencias
            if self._click_fila(num_lic):
                return True
            # link de paginación con el N destino más chico aún no visitado
            objetivo = None
            for a in pg.query_selector_all(f"{SEL_REC['grilla']} a"):
                try:
                    h = a.get_attribute("href") or ""
                except Exception:
                    continue
                m = re.search(r"Page\$(\d+)", h)
                if m:
                    npag = int(m.group(1))
                    if npag not in visitadas and (objetivo is None or npag < objetivo[0]):
                        objetivo = (npag, a)
            if objetivo is None:
                return False
            visitadas.add(objetivo[0])
            objetivo[1].click()
            pg.wait_for_timeout(1400)
            try:
                pg.wait_for_load_state("networkidle", timeout=8000)
            except PWTimeout:
                pass
        return False

    def procesar_fila(self, reg, enviar=False, prog=None):
        pg = self.page
        rut = str(reg.get("rut", "")).strip()
        num_lic = limpiar_num_licencia(reg.get("num_licencia"))
        if not rut_valido(rut):
            raise LicenciaError(f"RUT inválido: {rut}")
        if not num_lic:
            raise LicenciaError("Falta el N° de licencia en el Excel")

        # Empezar cada fila desde la página limpia (evita arrastrar el estado
        # de la fila anterior, que impedía reabrir el buscador).
        pg.goto(REC_URL, wait_until="domcontentloaded", timeout=45000)
        pg.wait_for_timeout(1500)

        if prog:
            prog(0.15, f"Buscando RUT {rut}...")
        # 1) Abrir buscador y buscar por RUT
        self._click_boton(SEL_REC["btn_consulta"])
        pg.wait_for_selector(SEL_REC["busca_rut"], state="visible", timeout=10000)
        pg.fill(SEL_REC["busca_rut"], _rut_busqueda(rut))
        self._click_boton(SEL_REC["btn_buscar"])
        pg.wait_for_timeout(2500)
        try:
            pg.wait_for_load_state("networkidle", timeout=8000)
        except PWTimeout:
            pass

        # 2) Ordenar por fecha desc (recientes primero) y seleccionar por N° licencia
        if prog:
            prog(0.4, f"Seleccionando licencia {num_lic}...")
        grid_vacio = self._grid_vacio()
        self._ordenar_fecha_desc()
        if not self._seleccionar_licencia(num_lic):
            if grid_vacio:
                raise LicenciaError(
                    f"El RUT {rut} no aparece en el buscador (Sin Datos): revisa que exista en el sistema.")
            raise LicenciaError(
                f"No encontré la licencia {num_lic} para el RUT {rut} en la grilla (revisa el N° de licencia).")
        pg.wait_for_timeout(2500)
        try:
            pg.wait_for_load_state("networkidle", timeout=8000)
        except PWTimeout:
            pass

        # Verificar que cargó la licencia correcta
        cargada = self._val(SEL_REC["num_licencia"])
        if cargada and normaliza(cargada) != normaliza(num_lic):
            raise LicenciaError(
                f"Se cargó la licencia {cargada} pero esperaba {num_lic}.")

        # 3) Valores que muestra el sitio (se guardan)
        datos_sitio = {
            "dias_licencia": self._val(SEL_REC["dias_licencia"]),
            "total_subsidio": self._val(SEL_REC["total_subsidio"]),
            "total_cotizacion": self._val(SEL_REC["total_cotizacion"]),
            "valor_recuperacion": self._val(SEL_REC["valor_recuperacion"]),
            "nombre": self._val(SEL_REC["nombre"]),
        }

        # 4) Detalle del Pago (desde el Excel)
        if prog:
            prog(0.65, "Completando Detalle del Pago...")
        # Total/Parcial: viene de la columna "RECUPERACION" del Excel. Un pago
        # TOTAL solo se puede grabar una vez por licencia, así que forzarlo
        # siempre (como se hacía antes) rechaza el grabado cuando la planilla
        # en realidad pedía un abono PARCIAL. Por defecto Total, por si algún
        # Excel viejo no trae esta columna.
        tipo_rec = normaliza(reg.get("tipo_recuperacion"))
        radio = SEL_REC["radio_parcial"] if "parcial" in tipo_rec else SEL_REC["radio_total"]
        try:
            pg.check(radio)
        except Exception:
            pass
        # Tipo de Pago (obligatorio)
        self._elegir_opcion(SEL_REC["tipo_pago"], reg.get("tipo_pago"))
        pg.wait_for_timeout(600)
        # Banco / N° transferencia (según corresponda). El banco es best-effort:
        # si el nombre del Excel no calza con las opciones, avisa pero no falla.
        avisos = []
        if reg.get("banco"):
            try:
                self._elegir_opcion(SEL_REC["banco"], reg.get("banco"), obligatorio=False)
            except LicenciaError as e:
                avisos.append(f"Banco no calzó: {reg.get('banco')}")
        self._fill_si(SEL_REC["ncheque"], reg.get("num_transferencia"))
        self._fill_si(SEL_REC["fecha_pago"], reg.get("fecha_pago"))
        self._fill_si(SEL_REC["dias_subsidio"], reg.get("dias_subsidio"))
        self._fill_si(SEL_REC["valor_subsidio"], reg.get("valor_subsidio"))
        self._fill_si(SEL_REC["dias_cotizacion"], reg.get("dias_cotizacion"))
        self._fill_si(SEL_REC["valor_cotizacion"], reg.get("valor_cotizacion"))
        self._fill_si(SEL_REC["valor_interes"], reg.get("valor_intereses"))
        self._fill_si(SEL_REC["valor_multa"], reg.get("valor_multa"))
        self._fill_si(SEL_REC["observacion"], reg.get("observacion"))

        resumen = {
            "fila_excel": reg.get("_fila_excel"),
            "fila": reg.get("_fila_excel"),
            "rut": rut,
            "num_licencia": num_lic,
            "nombre": datos_sitio["nombre"],
            "tipo_pago": reg.get("tipo_pago"),
            "tipo_recuperacion": "Parcial" if "parcial" in tipo_rec else "Total",
            "fecha_pago": reg.get("fecha_pago"),
            "dias_subsidio": reg.get("dias_subsidio"),
            "valor_subsidio": reg.get("valor_subsidio"),
            "dias_cotizacion": reg.get("dias_cotizacion"),
            "valor_cotizacion": reg.get("valor_cotizacion"),
            "valor_intereses": reg.get("valor_intereses"),
            "valor_multa": reg.get("valor_multa"),
            "banco": reg.get("banco"),
            "num_transferencia": reg.get("num_transferencia"),
            "observacion": reg.get("observacion"),
            **datos_sitio,
            "avisos": avisos,
            "enviado": False,
        }

        os.makedirs(CAPTURAS_DIR, exist_ok=True)
        etiqueta = f"rec_fila{reg.get('_fila_excel')}_{rut}"
        if not enviar:
            ruta = os.path.join(CAPTURAS_DIR, f"{etiqueta}.png")
            pg.screenshot(path=ruta, full_page=True)
            resumen["captura"] = ruta
            resumen["modo"] = "DRY-RUN (no se grabó)"
            if prog:
                prog(1.0, "Listo (prueba)")
            return resumen

        # 5) Grabar Detalle (envío real)
        if prog:
            prog(0.85, "Grabando detalle...")
        self._click_boton(SEL_REC["btn_graba_detalle"])
        pg.wait_for_timeout(2500)
        msg = self._cerrar_modal_exito() or self._texto_modal_visible()
        resumen["mensaje_grabar"] = msg
        m = normaliza(msg)
        if "error" in m and "grab" not in m:
            resumen["enviado"] = False
            resumen["comentario"] = f"Posible error al grabar: {msg}"
        else:
            resumen["enviado"] = True
            resumen["modo"] = "GRABADO"
        if prog:
            prog(1.0, "Listo")
        return resumen
