"""Kodi/Jellyfin/Emby compatible NFO generation."""

import math
import os
import re
import xml.etree.ElementTree as ET
from typing import List, Optional

from module.download_record import DownloadRecord

HASHTAG_RE = re.compile(r"(?<!\w)#\S+")
PROMOTION_KEYWORDS = (
    "点击下方",
    "评论区",
    "置顶",
    "预览视频",
    "支持一下",
    "谢谢大家",
)


def get_nfo_path(video_path: str) -> str:
    """Return the sidecar NFO path for a video path."""
    return os.path.splitext(video_path)[0] + ".nfo"


def clean_caption_line(line: str) -> str:
    """Remove hashtags and surrounding whitespace from one caption line."""
    return HASHTAG_RE.sub("", line).strip()


def extract_genres(caption: Optional[str]) -> List[str]:
    """Extract ordered unique genres from caption hashtags."""
    if not caption:
        return []

    genres: List[str] = []
    seen = set()
    for tag in HASHTAG_RE.findall(caption):
        genre = tag.lstrip("#").strip()
        if genre and genre not in seen:
            genres.append(genre)
            seen.add(genre)
    return genres


def is_promotional_line(line: str) -> bool:
    """Return True when a caption line is likely channel promotion text."""
    return any(keyword in line for keyword in PROMOTION_KEYWORDS)


def clean_caption(caption: Optional[str]) -> str:
    """Return media-library friendly caption text without tags or promo lines."""
    if not caption:
        return ""

    lines: List[str] = []
    for raw_line in caption.splitlines():
        line = clean_caption_line(raw_line)
        if not line or is_promotional_line(line):
            continue
        lines.append(line)

    paragraphs: List[str] = []
    current: List[str] = []
    for line in lines:
        if line:
            current.append(line)
        elif current:
            paragraphs.append("\n".join(current))
            current = []
    if current:
        paragraphs.append("\n".join(current))

    return "\n\n".join(paragraphs).strip()


def title_from_record(record: DownloadRecord) -> str:
    """Choose a human-readable title for the media library."""
    cleaned_caption = clean_caption(record.caption)
    if cleaned_caption:
        return cleaned_caption.splitlines()[0]
    if record.original_file_name:
        return os.path.splitext(record.original_file_name)[0]
    if record.chat_title:
        return f"{record.chat_title} {record.message_id}"
    return f"{record.chat_id} {record.message_id}"


def date_part(value: Optional[str]) -> Optional[str]:
    """Return YYYY-MM-DD from an ISO-like timestamp."""
    if not value:
        return None
    return value[:10]


def year_part(value: Optional[str]) -> Optional[str]:
    """Return YYYY from an ISO-like timestamp."""
    if not value:
        return None
    return value[:4]


def runtime_minutes(duration: Optional[int]) -> Optional[str]:
    """Convert seconds to rounded-up minutes for NFO runtime."""
    if not duration:
        return None
    return str(int(math.ceil(duration / 60.0)))


def add_text(parent, tag: str, text: Optional[str]):
    """Add an XML child only when text is meaningful."""
    if text is None or text == "":
        return
    child = ET.SubElement(parent, tag)
    child.text = str(text)


def build_video_nfo_xml(record: DownloadRecord) -> str:
    """Build Kodi/Jellyfin/Emby-compatible movie XML."""
    root = ET.Element("movie")
    title = title_from_record(record)
    plot = clean_caption(record.caption)
    add_text(root, "title", title)
    add_text(root, "plot", plot)

    unique_id = ET.SubElement(
        root,
        "uniqueid",
        {"type": "telegram", "default": "true"},
    )
    unique_id.text = f"{record.chat_id}_{record.message_id}"

    add_text(root, "premiered", date_part(record.message_date))
    add_text(root, "year", year_part(record.message_date))
    add_text(root, "runtime", runtime_minutes(record.duration))
    add_text(root, "studio", record.chat_title)
    for genre in extract_genres(record.caption):
        add_text(root, "genre", genre)

    return ET.tostring(root, encoding="unicode")


def write_video_nfo(record: DownloadRecord) -> str:
    """Write a sidecar NFO file for successful video records."""
    if (
        record.media_type != "video"
        or record.download_status != "success"
        or not record.local_path
    ):
        return ""

    nfo_path = get_nfo_path(record.local_path)
    nfo_dir = os.path.dirname(nfo_path)
    if nfo_dir:
        os.makedirs(nfo_dir, exist_ok=True)

    root = ET.fromstring(build_video_nfo_xml(record))
    tree = ET.ElementTree(root)
    tree.write(nfo_path, encoding="utf-8", xml_declaration=True)
    return nfo_path
