"""把文章正文 HTML 片段转换为 Markdown。

文章正文是若干 ``<p>`` 段落，内部可能含 ``<br>``、``<strong>``、``<a>``、
``<img>`` 等。本模块递归地把行内节点转成 Markdown，``<img>`` 通过
``resolve_image`` 回调决定最终链接（本地化或远程）。
"""

import re
from urllib.parse import urljoin

from bs4 import NavigableString, Tag

from config import BASE_URL

_WS_RE = re.compile(r"\s+")


def _abs(href: str) -> str:
    """把相对地址补成绝对 URL。"""
    if not href:
        return ""
    return urljoin(BASE_URL + "/", href)


def _inline(node, resolve_image) -> str:
    """递归转换单个节点为 Markdown 文本。"""
    if isinstance(node, NavigableString):
        return str(node)
    if not isinstance(node, Tag):
        return ""

    name = node.name
    if name == "br":
        return "\n"

    inner = "".join(_inline(c, resolve_image) for c in node.children)

    if name in ("strong", "b"):
        s = inner.strip()
        return f"**{s}**" if s else ""
    if name in ("em", "i"):
        s = inner.strip()
        return f"*{s}*" if s else ""
    if name == "a":
        text = inner.strip()
        href = _abs(node.get("href", ""))
        return f"[{text}]({href})" if text else ""
    if name == "img":
        src = _abs(node.get("src", ""))
        alt = (node.get("alt") or "").strip()
        return resolve_image(src, alt)

    # span / div / font / u 等容器：透传内容
    return inner


def blocks_to_markdown(elements, resolve_image) -> str:
    """把文章正文的块级元素（``<p>`` 与块级 ``<img>`` 等，按文档顺序）转为 Markdown。

    源页面的图表是 ``container-narrow`` 的直接子 ``<img>``，与 ``<p>`` 交替出现，
    因此必须按顺序遍历而非只取 ``<p>``。块内空白折叠为单空格，块间用空行分隔。
    """
    blocks: list[str] = []
    for el in elements:
        text = _WS_RE.sub(" ", _inline(el, resolve_image)).strip()
        if text:
            blocks.append(text)
    return "\n\n".join(blocks)
