"""Fetch specs from W3C public API."""

from __future__ import annotations

import re
import time as time_mod

import httpx
from rich.console import Console
from rich.progress import (
    BarColumn,
    MofNCompleteColumn,
    Progress,
    SpinnerColumn,
    TextColumn,
)

from ..config import Config
from .base import SourceDocument

W3C_API = "https://api.w3.org"

console = Console()

# AI/agent-relevant W3C groups with their full API type prefix
W3C_AI_GROUPS = {
    "webagents": "cg/webagents",                     # Autonomous Agents on the Web
    "agentprotocol": "cg/agentprotocol",             # AI Agent Protocol
    "agentic-arbitration": "cg/agentic-arbitration",  # Agentic Arbitration Protocol
    "ai-content-disclosure": "cg/ai-content-disclosure",
    "aikr": "cg/aikr",                               # AI Knowledge Representation
    "ai-web-visibility": "cg/ai-web-visibility",
    "aiwss": "cg/aiwss",                             # AI-Driven Web Standards
    "cogai": "cg/cogai",                             # Cognitive AI
    "credentials": "cg/credentials",                 # Credentials CG
    "did": "wg/did",                                 # Decentralized Identifier WG
    "vc": "wg/vc",                                   # Verifiable Credentials WG
    "webmachinelearning": "wg/webmachinelearning",   # Web Machine Learning WG
    "wot": "wg/wot",                                 # Web of Things WG
}


def _strip_html(html: str) -> str:
    """Minimal HTML tag stripper — no heavy dependencies."""
    text = re.sub(r"<script[^>]*>.*?</script>", "", html, flags=re.DOTALL)
    text = re.sub(r"<style[^>]*>.*?</style>", "", text, flags=re.DOTALL)
    text = re.sub(r"<[^>]+>", " ", text)
    text = re.sub(r"&nbsp;", " ", text)
    text = re.sub(r"&amp;", "&", text)
    text = re.sub(r"&lt;", "<", text)
    text = re.sub(r"&gt;", ">", text)
    text = re.sub(r"&#\d+;", "", text)
    text = re.sub(r"\s+", " ", text)
    return text.strip()


class W3CFetcher:
    """Fetch specs from the W3C public API (no auth needed).

    Two strategies:
    1. Browse /specifications paginated, filter client-side by keywords
    2. Fetch specs linked from known AI-relevant groups
    Both are combined for maximum coverage.
    """

    def __init__(self, config: Config | None = None):
        self.config = config or Config.load()
        self.client = httpx.Client(timeout=30, follow_redirects=True)

    def search(
        self, keywords: list[str], since: str | None = None
    ) -> list[SourceDocument]:
        """Fetch AI-relevant W3C specs via keyword search over /specifications."""
        seen: dict[str, SourceDocument] = {}
        kw_lower = [k.lower() for k in keywords]

        # Strategy 1: Paginate through /specifications, filter client-side
        console.print("  Searching W3C specifications catalog...")
        page = 1
        max_pages = 17  # ~1679 specs total
        checked = 0

        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            MofNCompleteColumn(),
            console=console,
        ) as progress:
            task = progress.add_task("W3C catalog...", total=max_pages)

            while page <= max_pages:
                progress.update(task, description=f"W3C catalog page {page}/{max_pages}")
                try:
                    resp = self.client.get(
                        f"{W3C_API}/specifications",
                        params={"format": "json", "page": page},
                        headers={"Accept": "application/json"},
                    )
                    resp.raise_for_status()
                    data = resp.json()
                except httpx.HTTPError as e:
                    console.print(f"[yellow]W3C API error on page {page}: {e}[/]")
                    break

                spec_list = data.get("_links", {}).get("specifications", [])
                if not spec_list:
                    break

                max_pages = data.get("pages", max_pages)
                progress.update(task, total=max_pages)

                for item in spec_list:
                    title = item.get("title", "")
                    href = item.get("href", "")
                    shortname = href.rstrip("/").split("/")[-1] if href else ""
                    if not shortname:
                        continue
                    checked += 1

                    # Quick keyword check on title
                    if not any(kw in title.lower() for kw in kw_lower):
                        continue

                    # Fetch detail for description, URL, dates
                    detail = self._fetch_spec_detail(shortname)
                    abstract = _strip_html(detail.get("description", title))
                    spec_url = detail.get("editor-draft") or detail.get("url") or f"https://www.w3.org/TR/{shortname}/"
                    date = detail.get("date", "")
                    status = detail.get("status", "")

                    if since and date and date < since:
                        continue

                    name = f"w3c-{shortname}"
                    if name not in seen:
                        seen[name] = SourceDocument(
                            name=name,
                            title=detail.get("title", title),
                            abstract=abstract,
                            source="w3c",
                            source_id=shortname,
                            source_url=spec_url,
                            time=date,
                            doc_status=status,
                        )

                    time_mod.sleep(0.15)

                progress.advance(task)
                page += 1
                time_mod.sleep(0.2)

        console.print(f"  Checked {checked} W3C specs, found [bold green]{len(seen)}[/] matching keywords")
        return list(seen.values())

    def _fetch_spec_detail(self, shortname: str) -> dict:
        """Fetch detail for a single spec."""
        try:
            resp = self.client.get(
                f"{W3C_API}/specifications/{shortname}",
                headers={"Accept": "application/json"},
            )
            resp.raise_for_status()
            data = resp.json()
            latest = data.get("_links", {}).get("latest-version", {})
            return {
                "description": data.get("description", ""),
                "title": data.get("title", shortname),
                "editor-draft": data.get("editor-draft", ""),
                "url": latest.get("href", ""),
                "status": latest.get("title", ""),
                "date": latest.get("href", "").rstrip("/").split("/")[-1] if latest.get("href") else "",
            }
        except httpx.HTTPError:
            return {}

    def download_text(self, doc: SourceDocument) -> str | None:
        """Fetch spec URL content and strip HTML to plain text."""
        url = doc.source_url
        if not url:
            return None
        try:
            resp = self.client.get(url)
            resp.raise_for_status()
            content_type = resp.headers.get("content-type", "")
            if "html" in content_type:
                return _strip_html(resp.text)[:50000]
            return resp.text[:50000]
        except httpx.HTTPError as e:
            console.print(f"[dim]Could not download text for {doc.name}: {e}[/]")
            return None

    def close(self) -> None:
        self.client.close()
