"""Detecta el tipo de contenido de una URL (webpage, pdf, markdown, text, code_repository)."""

import re
from urllib.parse import urlparse


# Patrones de repos de codigo por hostname
_CODE_REPO_HOSTS = {"github.com", "gitlab.com", "bitbucket.org", "codeberg.org"}

# Extensiones reconocidas → tipo
_EXT_TYPE_MAP = {
    ".pdf": "pdf",
    ".md": "markdown",
    ".markdown": "markdown",
    ".rst": "text",
    ".txt": "text",
    ".html": "webpage",
    ".htm": "webpage",
    ".xml": "text",
    ".json": "text",
    ".csv": "text",
    ".py": "text",
    ".js": "text",
    ".ts": "text",
    ".go": "text",
    ".rs": "text",
    ".cpp": "text",
    ".c": "text",
    ".java": "text",
    ".rb": "text",
    ".git": "code_repository",
}

# Content-Type header prefixes → tipo
_CONTENT_TYPE_MAP = {
    "application/pdf": "pdf",
    "text/markdown": "markdown",
    "text/x-markdown": "markdown",
    "text/plain": "text",
    "text/html": "webpage",
    "text/xml": "text",
    "application/xml": "text",
    "application/json": "text",
}


def _is_code_repo_url(parsed, path_segments: list[str]) -> bool:
    """Return True si la URL apunta a la raiz de un repositorio de codigo."""
    host = parsed.hostname or ""
    if host not in _CODE_REPO_HOSTS:
        return False
    # Acepta org/repo o org/repo/ o org/repo.git (2 segmentos minimos)
    if len(path_segments) < 2:
        return False
    # Rechaza sub-recursos conocidos: issues, pulls, blob, tree, releases, etc.
    _SUB_RESOURCES = {"issues", "pulls", "blob", "tree", "releases", "tags",
                      "commits", "compare", "wiki", "discussions", "actions",
                      "security", "pulse", "graphs", "-", "settings"}
    if len(path_segments) >= 3 and path_segments[2].rstrip(".git") in _SUB_RESOURCES:
        return False
    return True


def _is_ssh_git_url(url: str) -> bool:
    """Return True si la URL es un SSH git shorthand (git@host:path)."""
    return url.strip().startswith("git@")


def _type_from_extension(path: str) -> str | None:
    """Detecta tipo segun la extension del path de la URL. Retorna None si no aplica."""
    # Ignorar query string / fragment
    clean_path = path.split("?")[0].split("#")[0]
    for ext, url_type in _EXT_TYPE_MAP.items():
        if clean_path.lower().endswith(ext):
            return url_type
    return None


def _type_from_content_type(content_type_header: str) -> str:
    """Mapea un Content-Type header al tipo de URL."""
    ct = content_type_header.lower().split(";")[0].strip()
    for prefix, url_type in _CONTENT_TYPE_MAP.items():
        if ct.startswith(prefix):
            return url_type
    return "webpage"


def detect_url_type(url: str, timeout: float = 10.0) -> tuple[str, dict]:
    """Detecta el tipo de contenido de una URL.

    Algoritmo:
    1. Verificar si la URL es un patron de repo de codigo (git@, github.com/org/repo).
    2. Verificar extension en el path de la URL (.pdf, .md, .txt, .html, .git).
    3. Si no se determino: HTTP HEAD request para leer Content-Type header.
    4. Default: "webpage".

    Args:
        url: URL a analizar.
        timeout: Timeout en segundos para el HTTP HEAD request (si es necesario).

    Returns:
        Tuple de (tipo, metadata) donde tipo es uno de:
        "webpage", "pdf", "markdown", "text", "code_repository".
        metadata incluye la informacion disponible (extension, content_type, etc.).

    Raises:
        Exception: Si falla la conexion HTTP cuando es necesaria.
    """
    import httpx

    url = url.strip()
    metadata: dict = {"url": url}

    # 1. SSH git shorthand
    if _is_ssh_git_url(url):
        metadata["detection"] = "ssh_pattern"
        return "code_repository", metadata

    parsed = urlparse(url)
    path_segments = [s for s in parsed.path.split("/") if s]

    # 2. Code repo by URL pattern
    if _is_code_repo_url(parsed, path_segments):
        metadata["detection"] = "url_pattern"
        metadata["host"] = parsed.hostname
        return "code_repository", metadata

    # 3. Extension-based detection
    ext_type = _type_from_extension(parsed.path)
    if ext_type is not None:
        metadata["detection"] = "extension"
        metadata["path"] = parsed.path
        return ext_type, metadata

    # 4. HTTP HEAD request
    try:
        response = httpx.head(url, timeout=timeout, follow_redirects=True)
        content_type = response.headers.get("content-type", "")
        metadata["detection"] = "content_type_header"
        metadata["content_type"] = content_type
        metadata["status_code"] = response.status_code
        return _type_from_content_type(content_type), metadata
    except Exception as exc:
        raise Exception(f"detect_url_type: HEAD request failed for {url!r}: {exc}") from exc
