"""Lee el Excel de Recuperación de Licencias y entrega filas normalizadas.

Encabezados esperados (tolerante a acentos, mayúsculas y typos):
  N° Licencia, RUT Funcionario, Tipo de Pago, Banco, N° Transferencia,
  Fecha Pago, Días Subsidio, Días de Cotización, Valor Intereses,
  Valor Subsidios, Valor de Cotización, Valor Multa, Observación
"""
from datetime import datetime, date
import unicodedata
import openpyxl
from config import rut_valido, limpiar_num_licencia


def _rut_canon(rut):
    """RUT canónico (sin puntos/espacios, sin ceros a la izquierda) para
    detectar duplicados aunque vengan escritos distinto (ej. '09829369-8' y
    '9829369-8' son la misma persona)."""
    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}"


def _norm(s):
    """minúsculas, sin tildes, sin signos y sin letras repetidas seguidas:
    para comparar encabezados tolerando typos (ej. 'lIICENCIA' -> 'licencia')."""
    s = str(s or "").strip().lower()
    s = unicodedata.normalize("NFD", s)
    s = "".join(c for c in s if unicodedata.category(c) != "Mn")
    s = " ".join("".join(c if c.isalnum() else " " for c in s).split())
    # colapsar caracteres repetidos consecutivos (liicencia -> licencia)
    out = []
    for c in s:
        if not out or out[-1] != c:
            out.append(c)
    return "".join(out)


def _mapear_encabezado(h):
    """Devuelve la clave interna para un encabezado, usando palabras clave."""
    n = _norm(h)
    if not n:
        return None
    tiene = lambda *ws: all(w in n for w in ws)
    if tiene("licencia"):                         return "num_licencia"
    if tiene("rut") or tiene("run"):              return "rut"
    if tiene("tipo", "pago"):                     return "tipo_pago"
    if "recuperacion" in n:                       return "tipo_recuperacion"
    if tiene("transferencia") or tiene("cheque"): return "num_transferencia"
    if tiene("banco"):                            return "banco"
    if tiene("fecha", "pago"):                    return "fecha_pago"
    if tiene("dia", "subsidio"):                  return "dias_subsidio"
    if tiene("dia", "cotiz"):                     return "dias_cotizacion"
    if tiene("valor", "interes"):                 return "valor_intereses"
    if tiene("valor", "subsidio"):                return "valor_subsidio"
    if tiene("valor", "cotiz"):                   return "valor_cotizacion"
    if tiene("valor", "multa"):                   return "valor_multa"
    if "observ" in n or "obsrv" in n:             return "observacion"
    return None


REQUERIDAS = ["num_licencia", "rut"]
NUMERICAS = ["dias_subsidio", "dias_cotizacion", "valor_intereses",
             "valor_subsidio", "valor_cotizacion", "valor_multa"]


def _fmt_fecha(v):
    if isinstance(v, (datetime, date)):
        return v.strftime("%d-%m-%Y")
    return str(v).strip() if v is not None else ""


def _fmt(v):
    if v is None:
        return ""
    if isinstance(v, float) and v.is_integer():
        return str(int(v))
    return str(v).strip()


def _num(v):
    """Deja solo dígitos (quita puntos de miles, $, espacios). '71.864' -> '71864'."""
    s = _fmt(v)
    d = "".join(c for c in s if c.isdigit())
    return d


def leer_recuperaciones(ruta):
    wb = openpyxl.load_workbook(ruta, data_only=True)
    ws = wb.active
    filas = list(ws.iter_rows(values_only=True))
    if not filas:
        return []
    encabezados = list(filas[0])
    idx = {}
    for i, h in enumerate(encabezados):
        clave = _mapear_encabezado(h)
        if clave and clave not in idx:
            idx[clave] = i

    faltan = [k for k in REQUERIDAS if k not in idx]
    if faltan:
        raise ValueError(
            f"El Excel no tiene todas las columnas obligatorias. Faltan: {faltan}\n"
            f"Encabezados encontrados: {[_fmt(h) for h in encabezados]}"
        )

    registros = []
    for n, fila in enumerate(filas[1:], start=2):
        if fila is None or all(c is None or str(c).strip() == "" for c in fila):
            continue
        reg = {"_fila_excel": n}
        for clave, i in idx.items():
            valor = fila[i] if i < len(fila) else None
            if clave == "fecha_pago":
                reg[clave] = _fmt_fecha(valor)
            elif clave in NUMERICAS:
                reg[clave] = _num(valor)
            elif clave == "num_licencia":
                reg[clave] = limpiar_num_licencia(_fmt(valor))
            else:
                reg[clave] = _fmt(valor)
        # asegurar todas las claves presentes
        for k in ["tipo_pago", "tipo_recuperacion", "banco", "num_transferencia",
                  "fecha_pago", "observacion"] + NUMERICAS:
            reg.setdefault(k, "")

        reg["rut_valido"] = rut_valido(reg.get("rut"))
        avisos = []
        if not reg["rut_valido"]:
            avisos.append("RUT inválido")
        if not reg.get("num_licencia"):
            avisos.append("Falta N° de licencia")
        if not reg.get("tipo_pago"):
            avisos.append("Falta Tipo de Pago")
        tr = reg.get("tipo_recuperacion", "").strip().lower()
        if tr and "total" not in tr and "parcial" not in tr:
            avisos.append(
                f"Recuperación no reconocida ('{reg['tipo_recuperacion']}'): debe ser Total o Parcial")
        reg["avisos"] = avisos
        registros.append(reg)

    # Filas duplicadas de tipo TOTAL (mismo RUT + N° licencia): el sistema solo
    # permite UN pago tipo "Recuperación Total" por licencia, así que repetir
    # la misma fila no solo es inútil, sino que la 2ª en adelante siempre va a
    # fallar ("EL TIPO DE PAGO DE RECUPERACION TOTAL SOLO PERMITE UN PAGO") ->
    # se marcan para que el motor las salte en vez de gastar intentos reales.
    # OJO: esto NO aplica a pagos PARCIAL, que sí pueden tener varias filas
    # legítimas para la misma licencia (abonos sucesivos).
    vistos = {}
    for reg in registros:
        if not reg.get("rut_valido") or not reg.get("num_licencia"):
            continue
        if "total" not in reg.get("tipo_recuperacion", "").strip().lower():
            continue
        clave = (_rut_canon(reg["rut"]), reg["num_licencia"])
        if clave in vistos:
            reg["avisos"].append(
                f"Fila duplicada de tipo Total (mismo RUT + N° licencia que la fila {vistos[clave]})")
        else:
            vistos[clave] = reg["_fila_excel"]
    return registros


if __name__ == "__main__":
    import sys
    for r in leer_recuperaciones(sys.argv[1]):
        print(r)
