"""Generic RSS/Atom feed fetcher — for BBC, Nature, NPR, Guardian, etc."""

from __future__ import annotations

import re
from xml.etree import ElementTree as ET

from platoon.models import Item
from platoon.fetcher import Fetcher

# Common namespaces
_NS = {
    "atom": "http://www.w3.org/2005/Atom",
    "media": "http://search.yahoo.com/mrss/",
    "dc": "http://purl.org/dc/elements/1.1/",
    "content": "http://purl.org/rss/1.0/modules/content/",
}


def _extract_image(entry, ns: dict) -> str:
    """Try to extract image from RSS entry (media:thumbnail, media:content, enclosure)."""
    # media:thumbnail
    thumb = entry.find("media:thumbnail", ns)
    if thumb is not None:
        url = thumb.get("url", "")
        if url:
            return url

    # media:content with image type
    for mc in entry.findall("media:content", ns):
        if "image" in mc.get("type", "") or mc.get("medium") == "image":
            url = mc.get("url", "")
            if url:
                return url

    # enclosure with image type
    enc = entry.find("enclosure")
    if enc is not None and "image" in enc.get("type", ""):
        return enc.get("url", "")

    # Try extracting from description/content HTML
    for tag_name in ["description", "content:encoded"]:
        el = entry.find(tag_name, ns) if ":" in tag_name else entry.find(tag_name)
        if el is not None and el.text:
            img_match = re.search(r'<img[^>]+src=["\']([^"\']+)["\']', el.text)
            if img_match:
                return img_match.group(1)

    return ""


def _strip_html(text: str) -> str:
    return re.sub(r"<[^>]+>", "", text).strip()


def _parse_rss(xml_text: str, label: str, max_items: int) -> list[Item]:
    """Parse RSS 2.0 feed."""
    try:
        root = ET.fromstring(xml_text)
    except ET.ParseError:
        return []

    items = []
    channel = root.find("channel")
    if channel is None:
        return []

    for entry in channel.findall("item")[:max_items]:
        title_el = entry.find("title")
        link_el = entry.find("link")
        desc_el = entry.find("description")
        if title_el is None or link_el is None:
            continue

        title = (title_el.text or "").strip()
        link = (link_el.text or "").strip()
        if not link:
            link = entry.findtext("guid", "")

        desc = ""
        if desc_el is not None and desc_el.text:
            desc = _strip_html(desc_el.text)

        image_url = _extract_image(entry, _NS)

        items.append(Item(
            title=title,
            url=link,
            source=label,
            summary=desc[:400],
            image_url=image_url,
            tags=[label],
        ))

    return items


def _parse_atom(xml_text: str, label: str, max_items: int) -> list[Item]:
    """Parse Atom feed."""
    try:
        root = ET.fromstring(xml_text)
    except ET.ParseError:
        return []

    ns = _NS["atom"]
    items = []

    for entry in root.findall(f"{{{ns}}}entry")[:max_items]:
        title_el = entry.find(f"{{{ns}}}title")
        link_el = entry.find(f"{{{ns}}}link[@rel='alternate']")
        if link_el is None:
            link_el = entry.find(f"{{{ns}}}link")
        summary_el = entry.find(f"{{{ns}}}summary")
        content_el = entry.find(f"{{{ns}}}content")

        if title_el is None:
            continue

        title = (title_el.text or "").strip()
        link = link_el.get("href", "") if link_el is not None else ""
        desc = ""
        for el in [summary_el, content_el]:
            if el is not None and el.text:
                desc = _strip_html(el.text)
                break

        image_url = _extract_image(entry, _NS)

        items.append(Item(
            title=title,
            url=link,
            source=label,
            summary=desc[:400],
            image_url=image_url,
            tags=[label],
        ))

    return items


def fetch_rss_feeds(cfg: dict, fetcher: Fetcher) -> list[Item]:
    """Fetch multiple RSS/Atom feeds configured under 'feeds' key."""
    max_per = cfg.get("max_items_per_feed", 5)
    items = []

    for feed in cfg.get("feeds", []):
        url = feed["url"]
        label = feed.get("label", "RSS")
        print(f"Fetching RSS [{label}]...")
        resp = fetcher.get(url)
        if not resp:
            continue

        text = resp.text
        # Detect Atom vs RSS
        if "<feed" in text[:500]:
            parsed = _parse_atom(text, label, max_per)
        else:
            parsed = _parse_rss(text, label, max_per)

        print(f"  -> {len(parsed)} items")
        items.extend(parsed)

    return items
