# -*- coding: utf-8 -*-
"""
Integración con SourceForge: API best_release y scraping recursivo de archivos.

- obtener_info_sourceforge: última versión estable vía API.
- buscar_mejor_enlace_sourceforge: búsqueda recursiva en la sección de archivos
  cuando la API no devuelve el instalador esperado.
"""

import logging
import os
import re
from urllib.parse import urljoin

import requests
from bs4 import BeautifulSoup

from . import config
from . import utils


def _construir_info_sourceforge(proyecto, nombre, filename):
    """Construye el dict con url, filename y filepath para un release de SF."""
    clean_url = f"https://downloads.sourceforge.net/project/{proyecto}{filename}"
    basename = os.path.basename(filename)
    logging.info(f"{nombre} (SourceForge API): Archivo -> {basename}")
    logging.info(f"{nombre} (SourceForge API): URL -> {clean_url}")
    return {"url": clean_url, "filename": basename, "filepath": filename}


def obtener_info_sourceforge(proyecto, nombre):
    """
    Obtiene la última versión estable desde la API best_release.json de SourceForge.
    Prioriza la release para Windows si existe.

    Returns:
        dict con 'url', 'filename', 'filepath' o None.
    """
    try:
        api_url = f"https://sourceforge.net/projects/{proyecto}/best_release.json"
        headers = {
            "User-Agent": config.DEFAULT_HEADERS["User-Agent"],
            "Accept": "application/json",
        }
        logging.info(f"{nombre} (SourceForge): Consultando API best_release.json...")
        r = requests.get(api_url, headers=headers, timeout=15)
        r.raise_for_status()
        data = r.json()
        windows_release = data.get("platform_releases", {}).get("windows")
        if windows_release:
            filename = windows_release.get("filename", "")
            if filename:
                return _construir_info_sourceforge(proyecto, nombre, filename)
        release = data.get("release", {})
        if release:
            filename = release.get("filename", "")
            if filename:
                logging.warning(
                    f"{nombre} (SourceForge API): No release Windows específica, usando default"
                )
                return _construir_info_sourceforge(proyecto, nombre, filename)
        logging.warning(f"{nombre} (SourceForge API): No se encontró ningún release válido")
        return None
    except Exception as e:
        utils.registrar_error(f"Error obteniendo info de {nombre} desde SourceForge API: {e}")
        return None


def _extraer_version_de_enlace(href, pattern):
    """Extrae la versión de un href y normaliza separadores."""
    if not pattern:
        return None
    vmatch = re.search(pattern, href)
    if vmatch:
        version = vmatch.group(1) if vmatch.groups() else vmatch.group(0)
        return version.replace("_", ".").replace("-", ".")
    return None


def buscar_mejor_enlace_sourceforge(files_url, extension, pattern, headers, profundidad=0, max_profundidad=2):
    """
    Scraping recursivo en la sección de archivos de SourceForge para encontrar
    el mejor candidato de descarga (por extensión y patrón de versión).

    Returns:
        Lista de tuplas (version, url).
    """
    try:
        resp = requests.get(files_url, headers=headers, timeout=15)
        soup = BeautifulSoup(resp.content, "html.parser")
        candidatos = []
        for a in soup.find_all("a", href=True):
            href = a["href"]
            if re.search(r"/download$", href) and (not extension or extension in href):
                version = _extraer_version_de_enlace(href, pattern)
                candidatos.append((version or "", href))
        if candidatos:
            return candidatos
        for a in soup.find_all("a", href=True):
            href = a["href"]
            if extension and extension in href and not href.endswith("/"):
                download_href = href + "/download" if not href.endswith("/download") else href
                version = _extraer_version_de_enlace(href, pattern)
                candidatos.append((version or "", download_href))
        if candidatos:
            return candidatos
        if profundidad < max_profundidad:
            dirs_a_saltar = ["doc", "src", "source", "old", "test", "example", "sample"]
            for a in soup.find_all("a", href=True):
                href = a["href"]
                if href.endswith("/") and not href.startswith("..") and not href.startswith("/"):
                    if any(x in href.lower() for x in dirs_a_saltar):
                        continue
                    sub_url = urljoin(files_url, href)
                    sub_candidatos = buscar_mejor_enlace_sourceforge(
                        sub_url, extension, pattern, headers, profundidad + 1, max_profundidad
                    )
                    if sub_candidatos:
                        return sub_candidatos
        return []
    except Exception as e:
        utils.registrar_error(f"Error en scraping recursivo SourceForge: {e}")
        return []
