import gzip
import json
import sqlite3
import tempfile
import urllib.request
import shutil
from pathlib import Path
from datetime import datetime, timezone
from defusedxml.ElementTree import iterparse

CONFIG = Path("/etc/hermes-nexus/epg/sources.json")
DB = Path("/var/lib/hermes-nexus/epg.db")

MAX_DOWNLOAD = 250 * 1024 * 1024
MAX_UNCOMPRESSED = 1024 * 1024 * 1024

def iniciar_db():
    with sqlite3.connect(DB) as db:
        db.execute("""
            CREATE TABLE IF NOT EXISTS epg_programas (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                fuente TEXT NOT NULL,
                canal TEXT NOT NULL,
                titulo TEXT NOT NULL,
                inicio TEXT,
                fin TEXT,
                descripcion TEXT
            )
        """)
        db.execute("""
            CREATE INDEX IF NOT EXISTS idx_epg_busqueda
            ON epg_programas(titulo, inicio)
        """)

def descargar(url):
    req = urllib.request.Request(
        url,
        headers={"User-Agent": "HermesNexus-EPG/1.0"}
    )

    with tempfile.NamedTemporaryFile(delete=False) as tmp:
        archivo = Path(tmp.name)
        total = 0

        try:
            with urllib.request.urlopen(req, timeout=60) as r:
                while True:
                    bloque = r.read(1024 * 1024)
                    if not bloque:
                        break

                    total += len(bloque)
                    if total > MAX_DOWNLOAD:
                        raise ValueError("EPG supera el tamaño permitido")

                    tmp.write(bloque)

            return archivo

        except Exception:
            archivo.unlink(missing_ok=True)
            raise

def texto(elemento, etiqueta):
    nodo = elemento.find(etiqueta)
    return (nodo.text or "").strip() if nodo is not None else ""

def importar_fuente(fuente):
    archivo = descargar(fuente["url"])
    temporal_xml = None

    try:
        with archivo.open("rb") as f:
            comprimido = f.read(2) == b"\x1f\x8b"

        if comprimido:
            with tempfile.NamedTemporaryFile(delete=False) as tmp:
                temporal_xml = Path(tmp.name)
                total = 0

                with gzip.open(archivo, "rb") as entrada:
                    while True:
                        bloque = entrada.read(1024 * 1024)
                        if not bloque:
                            break

                        total += len(bloque)
                        if total > MAX_UNCOMPRESSED:
                            raise ValueError("XML descomprimido demasiado grande")

                        tmp.write(bloque)

            archivo_xml = temporal_xml
        else:
            archivo_xml = archivo

        iniciar_db()
        registros = []

        with sqlite3.connect(DB) as db:
            db.execute("BEGIN")
            db.execute(
                "DELETE FROM epg_programas WHERE fuente=?",
                (fuente["id"],)
            )

            for evento, elem in iterparse(
                str(archivo_xml),
                events=("end",)
            ):
                if elem.tag == "programme":
                    registros.append((
                        fuente["id"],
                        elem.attrib.get("channel", ""),
                        texto(elem, "title"),
                        elem.attrib.get("start", ""),
                        elem.attrib.get("stop", ""),
                        texto(elem, "desc")
                    ))

                    elem.clear()

                    if len(registros) >= 1000:
                        db.executemany("""
                            INSERT INTO epg_programas
                            (fuente, canal, titulo, inicio, fin, descripcion)
                            VALUES (?, ?, ?, ?, ?, ?)
                        """, registros)
                        registros.clear()

            if registros:
                db.executemany("""
                    INSERT INTO epg_programas
                    (fuente, canal, titulo, inicio, fin, descripcion)
                    VALUES (?, ?, ?, ?, ?, ?)
                """, registros)

            cantidad = db.execute(
                "SELECT COUNT(*) FROM epg_programas WHERE fuente=?",
                (fuente["id"],)
            ).fetchone()[0]

        return cantidad

    finally:
        archivo.unlink(missing_ok=True)
        if temporal_xml:
            temporal_xml.unlink(missing_ok=True)

def ejecutar():
    fuentes = json.loads(
        CONFIG.read_text(encoding="utf-8")
    )["sources"]

    for fuente in fuentes:
        if not fuente.get("enabled", True):
            continue

        try:
            cantidad = importar_fuente(fuente)
            print(fuente["id"], "PROGRAMAS:", cantidad)
        except Exception as e:
            print(fuente["id"], "ERROR:", type(e).__name__)

if __name__ == "__main__":
    ejecutar()
