#!/usr/bin/env python3
"""
Script para descargar boletines oficiales de San Luis.

Scraping del portal: https://boletinoficial.sanluis.gov.ar/Boletin/Periodo/YYYY-M
Descarga PDF vía:   https://boletinoficial.sanluis.gov.ar/Boletins/Numero/NUMERO

Uso:
    python descargar_sanluis.py                          # Descarga boletines del mes actual
    python descargar_sanluis.py --anio 2026              # Descarga todo el año 2026
    python descargar_sanluis.py --anio 2026 --mes 3      # Descarga todo marzo de 2026
    python descargar_sanluis.py --anio 2026 --mes 3 --dia 5  # Descarga el 05/03/2026
"""

import os
import sys
import re
import datetime
import argparse
from base import ya_existe_en_provincia
import calendar

import requests
from bs4 import BeautifulSoup

sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(__file__), '..', '.env'))

PDF_STORAGE_PATH = os.getenv('PDF_STORAGE_PATH', '/var/www/html/compartido/boletinesOficiales/pdf')
DESTINO = os.path.join(PDF_STORAGE_PATH, "SAN LUIS")

BASE_URL = "https://boletinoficial.sanluis.gov.ar"

SESSION = requests.Session()
SESSION.headers.update({
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Referer": BASE_URL,
})

# Meses en español para parsear las fechas del sitio (ej: "27 feb. 2026")
MESES_CORTOS = {
    'ene': 1, 'feb': 2, 'mar': 3, 'abr': 4,
    'may': 5, 'jun': 6, 'jul': 7, 'ago': 8,
    'sep': 9, 'oct': 10, 'nov': 11, 'dic': 12,
}


def parsear_fecha_sitio(texto):
    """
    Parsea fechas del sitio como '27 feb. 2026' o '5 mar. 2026'.
    Retorna datetime.date o None.
    """
    m = re.search(r'(\d{1,2})\s+(\w+)\.?\s+(\d{4})', texto.strip().lower())
    if not m:
        return None
    dia, mes_str, anio = int(m.group(1)), m.group(2)[:3], int(m.group(3))
    mes = MESES_CORTOS.get(mes_str)
    if not mes:
        return None
    try:
        return datetime.date(anio, mes, dia)
    except ValueError:
        return None


def obtener_boletines_periodo(anio, mes):
    """
    Scraping de la página del período para obtener los boletines listados.

    Returns:
        Lista de dicts {'numero': int, 'fecha': datetime.date}
    """
    url = f"{BASE_URL}/Boletin/Periodo/{anio}-{mes}"
    try:
        r = SESSION.get(url, timeout=30)
        r.raise_for_status()
    except requests.RequestException as e:
        print(f"  Error al obtener el listado del período {anio}-{mes}: {e}")
        return []

    soup = BeautifulSoup(r.text, "html.parser")
    boletines = []

    # Los links de descarga tienen la forma /Boletins/Numero/NUMERO
    for a in soup.find_all("a", href=re.compile(r'/Boletins/Numero/\d+')):
        m = re.search(r'/Boletins/Numero/(\d+)', a["href"])
        if not m:
            continue
        numero = int(m.group(1))

        # Buscar la fecha en el bloque contenedor del link
        contenedor = a.find_parent()
        fecha = None
        for _ in range(5):  # subir hasta 5 niveles buscando la fecha
            if contenedor is None:
                break
            texto = contenedor.get_text(" ", strip=True)
            fecha = parsear_fecha_sitio(texto)
            if fecha:
                break
            contenedor = contenedor.find_parent()

        # Evitar duplicados (algunos boletines tienen dos links VER y Descargar)
        if not any(b["numero"] == numero for b in boletines):
            boletines.append({"numero": numero, "fecha": fecha})

    return boletines


def nombre_destino(fecha):
    """Nombre estándar del archivo: sanluis_YYYY_MM_DD.pdf"""
    return f"sanluis_{fecha.strftime('%Y_%m_%d')}.pdf"


def descargar_pdf(numero, fecha, directorio):
    """
    Descarga el PDF de un boletín por su número.
    Retorna True si lo descargó, False si hubo error, None si ya existía.
    """
    nombre = nombre_destino(fecha)
    ruta = os.path.join(directorio, nombre)

    if ya_existe_en_provincia(directorio, nombre):
        print(f"  [SKIP] N° {numero} — ya existe: {nombre}")
        return None

    url = f"{BASE_URL}/Boletins/Numero/{numero}"
    try:
        r = SESSION.get(url, timeout=60, stream=True)
        r.raise_for_status()

        # Verificar que sea PDF real
        content_type = r.headers.get("Content-Type", "")
        primeros_bytes = b""
        chunks = []
        for chunk in r.iter_content(chunk_size=8192):
            chunks.append(chunk)
            if len(primeros_bytes) < 4:
                primeros_bytes += chunk
        contenido = b"".join(chunks)

        if not contenido[:4] == b"%PDF" and "pdf" not in content_type.lower():
            print(f"  [WARN] N° {numero} — la respuesta no parece un PDF (Content-Type: {content_type})")
            return False

        with open(ruta, "wb") as f:
            f.write(contenido)

        size_mb = os.path.getsize(ruta) / 1024 / 1024
        print(f"  [OK] N° {numero} — guardado: {nombre} ({size_mb:.1f} MB)")
        return True

    except requests.RequestException as e:
        print(f"  [ERROR] N° {numero} — {e}")
        return False





def main():
    parser = argparse.ArgumentParser(
        description="Descarga boletines oficiales de San Luis",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Ejemplos de uso:
  %(prog)s                              # Mes actual
  %(prog)s --anio 2026                  # Todo el año 2026
  %(prog)s --anio 2026 --mes 3         # Marzo de 2026
  %(prog)s --anio 2026 --mes 3 --dia 5 # 05/03/2026
        """
    )
    parser.add_argument("--anio", type=int, help="Año a descargar")
    parser.add_argument("--mes",  type=int, help="Mes a descargar (1-12)")
    parser.add_argument("--dia",  type=int, help="Día específico (1-31)")
    parser.add_argument("--directorio", type=str, default=DESTINO,
                        help="Directorio de destino")
    args = parser.parse_args()

    if args.mes is not None and (args.mes < 1 or args.mes > 12):
        parser.error("El mes debe estar entre 1 y 12")
    if args.dia is not None and (args.dia < 1 or args.dia > 31):
        parser.error("El día debe estar entre 1 y 31")
    if args.dia is not None and args.mes is None:
        parser.error("Si especificás un día, debés especificar también el mes")
    if args.mes is not None and args.anio is None:
        parser.error("Si especificás un mes, debés especificar también el año")

    hoy = datetime.date.today()
    anio = args.anio or hoy.year

    # Determinar meses a procesar
    if args.mes:
        meses = [args.mes]
    elif args.anio:
        meses = list(range(1, 13))
    else:
        meses = [hoy.month]

    print("=" * 60)
    print("  DESCARGA DE BOLETINES OFICIALES - SAN LUIS")
    print("=" * 60)

    os.makedirs(args.directorio, exist_ok=True)
    print(f"Directorio de destino: {args.directorio}")
    print()

    total = descargados = ya_existentes = errores = 0

    for mes in meses:
        print(f"--- Período {anio}-{mes:02d} ---")
        boletines = obtener_boletines_periodo(anio, mes)

        if not boletines:
            print(f"  No se encontraron boletines para {anio}-{mes:02d}")
            print()
            continue

        print(f"  Boletines encontrados: {len(boletines)}")

        # Filtrar por día si se especificó
        if args.dia:
            fecha_filtro = datetime.date(anio, mes, args.dia)
            boletines = [b for b in boletines if b["fecha"] == fecha_filtro]
            if not boletines:
                print(f"  No hay boletín para el {args.dia:02d}/{mes:02d}/{anio}")
                print()
                continue

        for b in sorted(boletines, key=lambda x: x["numero"]):
            fecha = b["fecha"] or datetime.date(anio, mes, 1)
            fecha_str = b["fecha"].strftime("%d/%m/%Y") if b["fecha"] else "fecha desconocida"
            print(f"  N° {b['numero']}  ({fecha_str})")
            total += 1
            resultado = descargar_pdf(b["numero"], fecha, args.directorio)
            if resultado is True:
                descargados += 1
            elif resultado is None:
                ya_existentes += 1
            else:
                errores += 1
        print()

    print("=" * 60)
    print("  RESUMEN")
    print("=" * 60)
    print(f"Total boletines encontrados: {total}")
    print(f"Descargados:                 {descargados}")
    print(f"Ya existían:                 {ya_existentes}")
    print(f"Errores:                     {errores}")
    print(f"Directorio:                  {args.directorio}")
    print()
    print("Proceso completado.")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\nDescarga interrumpida por el usuario")
        sys.exit(130)
    except Exception as e:
        print(f"\nError inesperado: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
