"""
comprimir_pdfs.py
-----------------
Recorre una carpeta raíz, busca el primer PDF dentro de cada subcarpeta
y lo comprime usando Ghostscript (método más efectivo) con fallback a pypdf.

Uso:
    python comprimir_pdfs.py "D:\\8.Omar 2026\\MININTERIOR\\Cuentas de Cobro\\4.Abril\\Evidencias\\OBLIGACIÓN 3"

Opciones de calidad (argumento --calidad):
    screen   → ~72 dpi  — muy pequeño, solo pantalla
    ebook    → ~150 dpi — buen balance tamaño/calidad  ✅ recomendado
    printer  → ~300 dpi — alta calidad, tamaño moderado
    prepress → ~300 dpi — máxima calidad, poco ahorro
"""

import os
import sys
import shutil
import subprocess
import argparse
from pathlib import Path

# ─────────────────────────────────────────────
# MÉTODO 1: Ghostscript (mejor compresión)
# ─────────────────────────────────────────────
def comprimir_con_ghostscript(input_path: Path, output_path: Path, calidad: str = "ebook") -> bool:
    """Comprime un PDF usando Ghostscript. Retorna True si tuvo éxito."""
    
    # Buscar Ghostscript en Windows
    gs_ejecutables = [
        "gswin64c",   # Ghostscript 64-bit (Windows)
        "gswin32c",   # Ghostscript 32-bit (Windows)
        "gs",         # Linux/Mac
    ]
    
    gs_cmd = None
    for exe in gs_ejecutables:
        if shutil.which(exe):
            gs_cmd = exe
            break
    
    # También buscar en rutas comunes de Windows
    if not gs_cmd:
        rutas_windows = [
            r"C:\Program Files\gs\gs10.03.1\bin\gswin64c.exe",
            r"C:\Program Files\gs\gs10.02.1\bin\gswin64c.exe",
            r"C:\Program Files\gs\gs10.01.2\bin\gswin64c.exe",
            r"C:\Program Files (x86)\gs\gs9.56.1\bin\gswin32c.exe",
        ]
        # Buscar cualquier versión instalada
        gs_base = Path(r"C:\Program Files\gs")
        if gs_base.exists():
            for version_dir in sorted(gs_base.iterdir(), reverse=True):
                candidate = version_dir / "bin" / "gswin64c.exe"
                if candidate.exists():
                    gs_cmd = str(candidate)
                    break
        
        if not gs_cmd:
            for ruta in rutas_windows:
                if Path(ruta).exists():
                    gs_cmd = ruta
                    break
    
    if not gs_cmd:
        return False  # Ghostscript no disponible
    
    comando = [
        gs_cmd,
        "-sDEVICE=pdfwrite",
        "-dCompatibilityLevel=1.4",
        f"-dPDFSETTINGS=/{calidad}",
        "-dNOPAUSE",
        "-dQUIET",
        "-dBATCH",
        f"-sOutputFile={output_path}",
        str(input_path),
    ]
    
    try:
        result = subprocess.run(comando, capture_output=True, text=True, timeout=120)
        return result.returncode == 0 and output_path.exists()
    except (subprocess.TimeoutExpired, FileNotFoundError):
        return False


# ─────────────────────────────────────────────
# MÉTODO 2: pypdf (fallback, compresión básica)
# ─────────────────────────────────────────────
def comprimir_con_pypdf(input_path: Path, output_path: Path) -> bool:
    """Comprime usando pypdf. Menos efectivo pero no requiere instalación extra."""
    try:
        from pypdf import PdfReader, PdfWriter
        
        reader = PdfReader(str(input_path))
        writer = PdfWriter()
        
        for page in reader.pages:
            # Comprimir objetos de la página
            page.compress_content_streams()
            writer.add_page(page)
        
        # Comprimir imágenes embebidas
        for page in writer.pages:
            for img in page.images:
                img.replace(img.image, quality=75)
        
        writer.add_metadata(reader.metadata or {})
        
        with open(output_path, "wb") as f:
            writer.write(f)
        
        return output_path.exists()
    
    except ImportError:
        print("  ⚠️  pypdf no instalado. Ejecuta: pip install pypdf pillow")
        return False
    except Exception as e:
        print(f"  ⚠️  Error pypdf: {e}")
        return False


# ─────────────────────────────────────────────
# LÓGICA PRINCIPAL
# ─────────────────────────────────────────────
def formatear_bytes(n: int) -> str:
    if n < 1024:
        return f"{n} B"
    elif n < 1024 ** 2:
        return f"{n/1024:.1f} KB"
    else:
        return f"{n/1024**2:.2f} MB"


def procesar_carpeta(raiz: str, calidad: str = "ebook", sobrescribir: bool = False):
    raiz_path = Path(raiz)
    
    if not raiz_path.exists():
        print(f"❌ La carpeta no existe: {raiz}")
        sys.exit(1)
    
    # Buscar subcarpetas con PDFs
    subcarpetas = sorted([d for d in raiz_path.iterdir() if d.is_dir()])
    
    if not subcarpetas:
        print("⚠️  No se encontraron subcarpetas.")
        return
    
    print(f"\n📁 Carpeta raíz : {raiz_path}")
    print(f"📊 Calidad       : {calidad}")
    print(f"📂 Subcarpetas   : {len(subcarpetas)}")
    print("=" * 65)
    
    total_original = 0
    total_comprimido = 0
    procesados = 0
    errores = 0
    
    for subcarpeta in subcarpetas:
        # Buscar PDFs en la subcarpeta (no recursivo, solo primer nivel)
        pdfs = list(subcarpeta.glob("*.pdf")) + list(subcarpeta.glob("*.PDF"))
        
        if not pdfs:
            print(f"  ⏭️  {subcarpeta.name} — sin PDF")
            continue
        
        pdf_original = pdfs[0]  # Tomar el primero si hay varios
        tam_original = pdf_original.stat().st_size
        
        # Nombre del archivo de salida
        nombre_salida = pdf_original.stem + "_comprimido.pdf"
        pdf_salida = subcarpeta / nombre_salida
        
        # Si ya existe y no se quiere sobrescribir, saltar
        if pdf_salida.exists() and not sobrescribir:
            print(f"  ✅ {subcarpeta.name}/{pdf_original.name} — ya comprimido (usa --sobrescribir para repetir)")
            continue
        
        print(f"  🔄 {subcarpeta.name}/{pdf_original.name} ({formatear_bytes(tam_original)}) ...", end="", flush=True)
        
        # Intentar con Ghostscript primero
        exito = comprimir_con_ghostscript(pdf_original, pdf_salida, calidad)
        metodo = "GS"
        
        # Fallback a pypdf
        if not exito:
            exito = comprimir_con_pypdf(pdf_original, pdf_salida)
            metodo = "pypdf"
        
        if exito and pdf_salida.exists():
            tam_nuevo = pdf_salida.stat().st_size
            ahorro = tam_original - tam_nuevo
            pct = (ahorro / tam_original * 100) if tam_original > 0 else 0
            
            # Si el "comprimido" es más grande, mejor dejar el original
            if tam_nuevo >= tam_original:
                pdf_salida.unlink()
                # Copiar el original con nombre comprimido
                shutil.copy2(pdf_original, pdf_salida)
                print(f" ⚠️  sin ahorro → copia del original [{metodo}]")
            else:
                total_original += tam_original
                total_comprimido += tam_nuevo
                procesados += 1
                print(f" ✅ {formatear_bytes(tam_nuevo)} (↓{pct:.0f}%) [{metodo}]")
        else:
            print(f" ❌ Error al comprimir")
            errores += 1
    
    # Resumen final
    print("=" * 65)
    print(f"\n📈 RESUMEN:")
    print(f"   Procesados  : {procesados}")
    print(f"   Errores     : {errores}")
    if procesados > 0:
        ahorro_total = total_original - total_comprimido
        pct_total = (ahorro_total / total_original * 100) if total_original > 0 else 0
        print(f"   Tamaño antes: {formatear_bytes(total_original)}")
        print(f"   Tamaño después: {formatear_bytes(total_comprimido)}")
        print(f"   Ahorro total: {formatear_bytes(ahorro_total)} ({pct_total:.1f}%)")
    
    if errores > 0:
        print(f"\n💡 Para mejor compresión, instala Ghostscript:")
        print(f"   https://www.ghostscript.com/releases/gsdnld.html")
        print(f"   Luego vuelve a ejecutar el script.")


# ─────────────────────────────────────────────
# PUNTO DE ENTRADA
# ─────────────────────────────────────────────
if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Comprime PDFs en subcarpetas manteniendo legibilidad."
    )
    parser.add_argument(
        "carpeta",
        nargs="?",
        default=r"D:\8.Omar 2026\MININTERIOR\Cuentas de Cobro\4.Abril\Evidencias\OBLIGACIÓN 3",
        help="Ruta a la carpeta raíz con subcarpetas que contienen PDFs"
    )
    parser.add_argument(
        "--calidad",
        choices=["screen", "ebook", "printer", "prepress"],
        default="ebook",
        help="Calidad de compresión (default: ebook — mejor balance)"
    )
    parser.add_argument(
        "--sobrescribir",
        action="store_true",
        help="Sobreescribir archivos ya comprimidos"
    )
    
    args = parser.parse_args()
    procesar_carpeta(args.carpeta, args.calidad, args.sobrescribir)
