"""Content ingestion — fetch, extract, screenshot, archive."""

import logging
import re
import uuid
from html.parser import HTMLParser
from io import StringIO
from urllib.parse import urlparse

import httpx

from app.config import BROWSERLESS_URL
from app.services.storage import storage

log = logging.getLogger(__name__)


class _HTMLTextExtractor(HTMLParser):
    """Simple HTML to text converter."""
    def __init__(self):
        super().__init__()
        self._result = StringIO()
        self._skip = False
        self._skip_tags = {"script", "style", "noscript", "svg"}

    def handle_starttag(self, tag, attrs):
        if tag in self._skip_tags:
            self._skip = True

    def handle_endtag(self, tag):
        if tag in self._skip_tags:
            self._skip = False
        if tag in ("p", "div", "br", "h1", "h2", "h3", "h4", "li", "tr"):
            self._result.write("\n")

    def handle_data(self, data):
        if not self._skip:
            self._result.write(data)

    def get_text(self) -> str:
        raw = self._result.getvalue()
        # Collapse whitespace
        lines = [line.strip() for line in raw.splitlines()]
        return "\n".join(line for line in lines if line)


def html_to_text(html: str) -> str:
    extractor = _HTMLTextExtractor()
    extractor.feed(html)
    return extractor.get_text()


def extract_title_from_html(html: str) -> str | None:
    match = re.search(r"<title[^>]*>(.*?)</title>", html, re.IGNORECASE | re.DOTALL)
    return match.group(1).strip() if match else None


def extract_meta_description(html: str) -> str | None:
    match = re.search(
        r'<meta[^>]*name=["\']description["\'][^>]*content=["\'](.*?)["\']',
        html, re.IGNORECASE | re.DOTALL,
    )
    return match.group(1).strip() if match else None


async def fetch_url_content(url: str) -> dict:
    """Fetch URL content. Returns dict with html, text, title, description, used_browserless."""
    result = {"html": None, "text": None, "title": None, "description": None, "used_browserless": False}

    # Try HTTP-first extraction
    try:
        async with httpx.AsyncClient(timeout=15, follow_redirects=True) as client:
            resp = await client.get(url, headers={
                "User-Agent": "Mozilla/5.0 (compatible; SecondBrain/1.0)"
            })
            resp.raise_for_status()
            html = resp.text
            result["html"] = html
            result["text"] = html_to_text(html)
            result["title"] = extract_title_from_html(html)
            result["description"] = extract_meta_description(html)

            # If extraction is weak (< 200 chars of text), try browserless
            if len(result["text"] or "") < 200:
                log.info(f"Weak extraction ({len(result['text'] or '')} chars), trying browserless")
                br = await fetch_with_browserless(url)
                if br and len(br.get("text", "")) > len(result["text"] or ""):
                    result.update(br)
                    result["used_browserless"] = True

    except Exception as e:
        log.warning(f"HTTP fetch failed for {url}: {e}, trying browserless")
        try:
            br = await fetch_with_browserless(url)
            if br:
                result.update(br)
                result["used_browserless"] = True
        except Exception as e2:
            log.error(f"Browserless also failed for {url}: {e2}")

    return result


async def fetch_with_browserless(url: str) -> dict | None:
    """Use browserless/chrome to render JS-heavy pages."""
    try:
        async with httpx.AsyncClient(timeout=30) as client:
            resp = await client.post(
                f"{BROWSERLESS_URL}/content",
                json={"url": url, "waitForTimeout": 3000},
            )
            if resp.status_code == 200:
                html = resp.text
                return {
                    "html": html,
                    "text": html_to_text(html),
                    "title": extract_title_from_html(html),
                    "description": extract_meta_description(html),
                }
    except Exception as e:
        log.error(f"Browserless fetch failed: {e}")
    return None


async def take_screenshot(url: str, item_id: str) -> str | None:
    """Take a screenshot of a URL using browserless. Returns storage path or None."""
    try:
        async with httpx.AsyncClient(timeout=30) as client:
            resp = await client.post(
                f"{BROWSERLESS_URL}/screenshot",
                json={
                    "url": url,
                    "options": {"type": "png", "fullPage": False},
                    "waitForTimeout": 3000,
                },
            )
            if resp.status_code == 200:
                path = storage.save(
                    item_id=item_id,
                    asset_type="screenshot",
                    filename="screenshot.png",
                    data=resp.content,
                )
                return path
    except Exception as e:
        log.error(f"Screenshot failed for {url}: {e}")
    return None


async def archive_html(html: str, item_id: str) -> str | None:
    """Save the full HTML as an archived asset."""
    if not html:
        return None
    try:
        path = storage.save(
            item_id=item_id,
            asset_type="archived_html",
            filename="page.html",
            data=html.encode("utf-8"),
        )
        return path
    except Exception as e:
        log.error(f"HTML archive failed: {e}")
    return None
