"""Validacion best-effort del documento de identidad adjuntado al firmar: intenta leer el
texto de la imagen o PDF con OCR (Tesseract, via pytesseract) y compara contra el nombre y
numero de documento que el prestamista ya registro para esa persona.

Este modulo esta pensado para hosting compartido sin acceso root (no se puede garantizar
que el binario de Tesseract este instalado en el servidor): si no esta disponible o el
archivo no se puede procesar, la validacion se OMITE en silencio y el documento se acepta
igual. Es mejor aceptar sin validar automaticamente que bloquear la firma de alguien por una
limitacion de infraestructura que esta fuera de su control."""
import re
import unicodedata

try:
    import pytesseract
    from PIL import Image
    LIBRERIAS_DISPONIBLES = True
except ImportError:
    LIBRERIAS_DISPONIBLES = False


def _normalizar(texto):
    """Quita tildes, pasa a mayusculas y deja solo letras/digitos/espacios, para comparar
    de forma tolerante a diferencias de acentos, mayusculas y puntuacion del OCR."""
    if not texto:
        return ""
    texto = unicodedata.normalize("NFKD", texto).encode("ascii", "ignore").decode("ascii")
    texto = re.sub(r"[^A-Za-z0-9\s]", " ", texto)
    return texto.upper()


def _extraer_texto(ruta_archivo, extension):
    if extension == ".pdf":
        import fitz  # PyMuPDF: renderiza el PDF a imagen sin depender de binarios externos (poppler)
        texto_total = ""
        documento = fitz.open(ruta_archivo)
        try:
            for pagina in documento:
                pix = pagina.get_pixmap(dpi=200)
                imagen = Image.frombytes("RGB", [pix.width, pix.height], pix.samples)
                texto_total += "\n" + pytesseract.image_to_string(imagen, lang="spa+eng")
        finally:
            documento.close()
        return texto_total
    imagen = Image.open(ruta_archivo)
    return pytesseract.image_to_string(imagen, lang="spa+eng")


def ocr_disponible():
    """Prueba en caliente si el binario de Tesseract esta instalado en este servidor
    (las librerias de Python pueden estar instaladas sin que el binario lo este)."""
    if not LIBRERIAS_DISPONIBLES:
        return False
    try:
        pytesseract.get_tesseract_version()
        return True
    except Exception:
        return False


def validar_documento_identidad(ruta_archivo, extension, nombre_esperado, numero_documento_esperado):
    """Devuelve (ok, mensaje_error). ok=True cuando coincide O cuando no se pudo validar
    (OCR no disponible en este servidor, o el archivo no se pudo leer); ok=False SOLO
    cuando si se pudo leer el documento pero claramente no corresponde a esta persona."""
    if not ocr_disponible():
        return True, None

    try:
        texto = _extraer_texto(ruta_archivo, extension)
    except Exception:
        return True, None

    texto_normalizado = _normalizar(texto)
    if not texto_normalizado.strip():
        # No se logro extraer nada de texto (foto borrosa, mal enfocada, escaneo en blanco...):
        # no es un rechazo por no-coincidencia, sino por documento illegible.
        return False, (
            "No pudimos leer el contenido de la foto o PDF que adjuntaste. Sube una foto "
            "más clara y bien enfocada de tu documento de identidad."
        )

    numero_normalizado = re.sub(r"\D", "", numero_documento_esperado or "")
    if numero_normalizado and numero_normalizado not in re.sub(r"\D", "", texto_normalizado):
        return False, (
            f"No pudimos confirmar que el número de documento en la foto o PDF coincida con "
            f"el número registrado ({numero_documento_esperado}). Sube una foto o PDF más clara "
            f"donde se alcance a leer el número de documento."
        )

    palabras_nombre = [p for p in _normalizar(nombre_esperado).split() if len(p) > 2]
    if palabras_nombre:
        coincidencias = sum(1 for p in palabras_nombre if p in texto_normalizado)
        if coincidencias < max(1, len(palabras_nombre) // 2):
            return False, (
                f"No pudimos confirmar que el nombre en la foto o PDF coincida con el nombre "
                f"registrado ({nombre_esperado}). Sube una foto o PDF más clara donde se alcance "
                f"a leer el nombre completo."
            )

    return True, None
