#!/usr/bin/env python3
"""Descarga articulos de Wikipedia en espanol sobre los temas de JARVIS y los
deja como .txt en la carpeta de documentos del RAG. Luego, construir_indice.py
los vectoriza. Corre en el host (solo stdlib + red), sin sonido ni GPU.

    python3 config/wiki_ingesta.py            # descarga
    # despues, dentro del flatpak:
    flatpak run --command=python3 io.github.qwersyk.Newelle//master \
        ~/COFRE/CODERS/JARVIS/config/construir_indice.py

Es aditivo: agrega ficheros a la carpeta, no borra lo que ya haya.
"""
import os, json, time, urllib.parse, urllib.request, urllib.error

API = "https://es.wikipedia.org/w/api.php"
UA = "JARVIS-local-RAG/1.0 (asistente de voz local; contacto: local)"
DOCS = os.path.expanduser(
    "~/.var/app/io.github.qwersyk.Newelle/config/models/documents")

# Por tema: semillas seguras + una busqueda que amplia con articulos afines.
TEMAS = {
    "tecnologia": {
        "buscar": ["tecnología", "informática", "hardware", "red informática",
                   "inteligencia artificial", "sistema operativo"],
        "semillas": ["Tecnología", "Informática", "Internet", "Protocolo de red",
                     "Microprocesador", "Computación en la nube", "Base de datos"],
    },
    "criptografia": {
        "buscar": ["criptografía", "cifrado", "criptografía asimétrica"],
        "semillas": ["Criptografía", "Cifrado", "RSA", "Advanced Encryption Standard",
                     "Función hash criptográfica", "Firma digital",
                     "Diffie-Hellman", "Pretty Good Privacy", "Transport Layer Security",
                     "Criptografía de curva elíptica", "Cadena de bloques",
                     "Bitcoin", "Criptomoneda"],
    },
    "software_libre": {
        "buscar": ["software libre", "código abierto", "historia de Linux"],
        "semillas": ["Software libre", "GNU", "Richard Stallman", "GNU/Linux",
                     "Linus Torvalds", "Free Software Foundation", "Licencia pública general de GNU",
                     "Código abierto", "Debian", "Unix", "Kernel Linux",
                     "Movimiento del software libre"],
    },
    "hacking": {
        "buscar": ["seguridad informática", "hacker", "ciberseguridad"],
        "semillas": ["Hacker", "Seguridad informática", "Hacker (seguridad informática)",
                     "Malware", "Exploit", "Ingeniería social (seguridad informática)",
                     "Phreaking", "Kevin Mitnick", "Anonymous (colectivo)",
                     "Prueba de penetración", "Vulnerabilidad (informática)",
                     "Cortafuegos (informática)", "Ataque de denegación de servicio"],
    },
    "clima": {
        "buscar": ["cambio climático", "calentamiento global", "clima"],
        "semillas": ["Cambio climático", "Calentamiento global", "Efecto invernadero",
                     "Gas de efecto invernadero", "Protocolo de Kioto",
                     "Acuerdo de París", "IPCC", "Clima", "Dióxido de carbono",
                     "El Niño", "Nivel del mar", "Energía renovable"],
    },
    "conflictos_espana": {
        "buscar": ["guerra en España", "conflicto España historia"],
        "semillas": ["Guerra civil española", "Transición española",
                     "Guerra de la Independencia Española", "Guerras carlistas",
                     "Reconquista", "Dictadura de Francisco Franco",
                     "Segunda República Española", "Movimiento 15-M",
                     "Conflicto vasco", "Guerra de Sucesión Española"],
    },
}

BUSCAR_POR_CONSULTA = 15   # articulos extra por cada busqueda
PAUSA = 0.8                # cortesia con la API (subida tras el 429)


def _get(params, reintentos=5):
    params = {**params, "format": "json"}
    url = API + "?" + urllib.parse.urlencode(params)
    req = urllib.request.Request(url, headers={"User-Agent": UA})
    espera = 2.0
    for intento in range(reintentos):
        try:
            with urllib.request.urlopen(req, timeout=30) as r:
                return json.load(r)
        except urllib.error.HTTPError as e:
            if e.code == 429 and intento < reintentos - 1:
                # Wikipedia nos frena: esperar cada vez mas (backoff)
                time.sleep(espera)
                espera *= 2
                continue
            raise
    raise RuntimeError("agotados los reintentos")


def titulos_de_busqueda(consulta, limite):
    try:
        d = _get({"action": "query", "list": "search",
                  "srsearch": consulta, "srlimit": limite})
        return [h["title"] for h in d.get("query", {}).get("search", [])]
    except Exception as e:
        print(f"  busqueda '{consulta}' fallo: {e}")
        return []


def extracto(titulo):
    try:
        d = _get({"action": "query", "prop": "extracts", "explaintext": 1,
                  "redirects": 1, "titles": titulo})
        paginas = d.get("query", {}).get("pages", {})
        for _, pg in paginas.items():
            txt = pg.get("extract", "")
            if txt and len(txt) > 300:
                return pg.get("title", titulo), txt
    except Exception as e:
        print(f"  extracto '{titulo}' fallo: {e}")
    return None, None


def slug(s):
    s = "".join(c if c.isalnum() else "_" for c in s.lower())
    return s.strip("_")[:80]


def main():
    os.makedirs(DOCS, exist_ok=True)
    total = 0
    for tema, cfg in TEMAS.items():
        print(f"\n=== {tema} ===")
        titulos = list(cfg["semillas"])
        for consulta in cfg["buscar"]:
            titulos += titulos_de_busqueda(consulta, BUSCAR_POR_CONSULTA)
            time.sleep(PAUSA)
        # dedup conservando orden
        vistos, unicos = set(), []
        for t in titulos:
            if t.lower() not in vistos:
                vistos.add(t.lower()); unicos.append(t)
        for t in unicos:
            dst = os.path.join(DOCS, f"wiki_{tema}_{slug(t)}.txt")
            if os.path.exists(dst):
                continue
            titulo_real, txt = extracto(t)
            time.sleep(PAUSA)
            if not txt:
                continue
            with open(dst, "w", encoding="utf-8") as f:
                f.write(f"# {titulo_real}\n(Wikipedia, tema: {tema})\n\n{txt}\n")
            total += 1
            print(f"  [{total}] {titulo_real}  ({len(txt)//1024} KB)")
    print(f"\nlisto: {total} articulos nuevos en {DOCS}")


if __name__ == "__main__":
    main()
