# -*- coding: utf-8 -*-
"""论坛主题列表解析 - 复用自 pm001-crawler"""

from __future__ import annotations

import re
from dataclasses import dataclass
from datetime import datetime
from urllib.parse import parse_qs, unquote, urljoin, urlparse
from zoneinfo import ZoneInfo

from bs4 import BeautifulSoup, Tag
from dateutil import parser as date_parser


TOPIC_LINK_PATTERN = re.compile(r"dispbbs\.asp\?", re.IGNORECASE)
AUTHOR_LINK_PATTERN = re.compile(r"dispuser\.asp\?", re.IGNORECASE)
DATE_PATTERN = re.compile(r"\d{4}/\d{1,2}/\d{1,2}\s+\d{1,2}:\d{2}(?::\d{2})?")
ASIA_SHANGHAI = ZoneInfo("Asia/Shanghai")


@dataclass(slots=True)
class TopicEntry:
    topic_id: int
    board_id: int
    title: str
    url: str
    author_key: str
    author_name: str
    profile_url: str | None
    last_update_time: datetime


def parse_topic_list(html: str, board_id: int, base_url: str) -> list[TopicEntry]:
    """从板块列表页解析主题条目和对应作者信息。"""
    soup = BeautifulSoup(html, "lxml")
    topics: list[TopicEntry] = []
    seen_topic_ids: set[int] = set()

    for anchor in soup.find_all("a", href=TOPIC_LINK_PATTERN):
        topic_id = extract_topic_id(anchor.get("href", ""))
        if topic_id is None or topic_id in seen_topic_ids:
            continue

        title_container = anchor.find_parent("div", class_="listtitle")
        title = " ".join(anchor.stripped_strings).strip()
        if not title or title in {"树形", "打印"}:
            continue
        if title_container is None and DATE_PATTERN.fullmatch(title):
            continue
        if title_container is None and anchor.find_parent("div", class_="list_s") is not None:
            continue

        container = find_topic_container(anchor if title_container is None else title_container)
        if container is None:
            continue

        row_text = container.get_text("\n", strip=True)
        last_update = parse_last_update(row_text)
        if last_update is None:
            continue

        author_key, author_name, profile_url = extract_author(container, anchor, base_url)
        if not author_key or not author_name:
            continue

        seen_topic_ids.add(topic_id)
        topics.append(
            TopicEntry(
                topic_id=topic_id,
                board_id=board_id,
                title=title,
                url=urljoin(base_url, anchor["href"]),
                author_key=author_key,
                author_name=author_name,
                profile_url=profile_url,
                last_update_time=last_update,
            )
        )

    return topics


def extract_topic_id(href: str) -> int | None:
    """从主题链接中提取主题 ID。"""
    query = parse_qs(urlparse(href).query)
    values = query.get("ID") or query.get("id")
    if not values:
        return None
    try:
        return int(values[0])
    except ValueError:
        return None


def parse_last_update(text: str) -> datetime | None:
    """从文本中解析主题最后更新时间。"""
    matches = DATE_PATTERN.findall(text)
    if not matches:
        return None
    try:
        value = date_parser.parse(matches[-1])
    except (ValueError, TypeError, OverflowError):
        return None
    if value.tzinfo is None:
        value = value.replace(tzinfo=ASIA_SHANGHAI)
    return value.astimezone(ASIA_SHANGHAI)


def find_topic_container(anchor: Tag) -> Tag | None:
    """定位主题条目对应的容器节点，便于提取更新时间和作者信息。"""
    current = anchor
    while current is not None:
        classes = current.get("class", [])
        if current.name == "div" and any(name in {"list", "list_r1"} for name in classes):
            return current
        current = current.parent if isinstance(current.parent, Tag) else None

    for name in ("tr", "table", "div", "li"):
        container = anchor.find_parent(name)
        if container is not None and len(container.get_text(" ", strip=True)) > len(anchor.get_text(" ", strip=True)):
            return container
    return None


def extract_author(container: Tag, topic_anchor: Tag, base_url: str) -> tuple[str | None, str | None, str | None]:
    """从主题容器中提取作者名称、作者标识和作者主页链接。"""
    anchors = [a for a in container.find_all("a", href=True)]
    topic_index = next((idx for idx, item in enumerate(anchors) if item is topic_anchor), None)
    candidates = anchors[:topic_index] if topic_index is not None else anchors
    author_links = [a for a in candidates if AUTHOR_LINK_PATTERN.search(a.get("href", ""))]
    if not author_links:
        author_links = [a for a in anchors if AUTHOR_LINK_PATTERN.search(a.get("href", ""))]
    if not author_links:
        return None, None, None

    author_anchor = author_links[0]
    name = " ".join(author_anchor.stripped_strings).strip()
    href = author_anchor.get("href", "")
    key = extract_author_key(href)
    if not key or not name:
        return None, None, None
    return key, name, urljoin(base_url, href)


def extract_author_key(href: str) -> str | None:
    """从作者链接中提取作者唯一标识。"""
    query = parse_qs(urlparse(href).query)
    if "id" in query and query["id"]:
        return f"id:{query['id'][0]}"
    if "name" in query and query["name"]:
        return f"name:{unquote(query['name'][0])}"
    return None
