"""Caption rendering, buttons and cover resolution (pure functions)."""

from __future__ import annotations

import re
from datetime import UTC, datetime
from typing import Any
from urllib.parse import urlsplit

from app.database.models import MediaAsset, Post

_PLACEHOLDER_RE = re.compile(r"\{([a-z_]+)\}")
_CONTROL_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]")

DEFAULT_CAPTION_TEMPLATE = """🎬 {title}

{description}

▶️ مشاهده ویدیو:
{video_link}"""

SUPPORTED_VARIABLES = (
    "title",
    "description",
    "video_link",
    "post_id",
    "publish_date",
    "channel_name",
    "channel_username",
    "brand",
    "media_file_name",
)


def sanitize_text(value: str | None, *, limit: int = 4096) -> str:
    if not value:
        return ""
    text = _CONTROL_RE.sub("", str(value)).replace("\r\n", "\n").replace("\r", "\n")
    text = text.strip()
    if len(text) > limit:
        text = text[: max(0, limit - 1)].rstrip() + "…"
    return text


def render_caption(
    *,
    template: str,
    title: str | None,
    description: str | None,
    video_link: str | None,
    post_id: int,
    publish_date: datetime | None,
    channel_name: str | None,
    channel_username: str | None,
    brand: str | None,
    media_file_name: str | None,
    prefix: str = "",
    suffix: str = "",
    signature: str = "",
    max_length: int = 1024,
) -> str:
    values: dict[str, str] = {
        "title": sanitize_text(title, limit=255) or "بدون عنوان",
        "description": sanitize_text(description, limit=3000),
        "video_link": video_link or "",
        "post_id": str(post_id),
        "publish_date": (publish_date or datetime.now(UTC)).strftime("%Y-%m-%d %H:%M"),
        "channel_name": sanitize_text(channel_name, limit=255),
        "channel_username": sanitize_text(channel_username, limit=64),
        "brand": sanitize_text(brand, limit=255),
        "media_file_name": sanitize_text(media_file_name, limit=255),
    }

    def replace(match: re.Match[str]) -> str:
        key = match.group(1)
        return values.get(key, match.group(0))

    body = _PLACEHOLDER_RE.sub(replace, template or DEFAULT_CAPTION_TEMPLATE)
    parts = [sanitize_text(prefix, limit=1024), body]
    parts.append(sanitize_text(suffix, limit=1024))
    if signature and sanitize_text(signature) not in body:
        parts.append(sanitize_text(signature, limit=1024))
    text = "\n\n".join(part for part in parts if part.strip())
    return sanitize_text(text, limit=max_length)


def parse_buttons(raw: Any) -> list[tuple[str, str]]:
    """Validate a JSON-like button list. Invalid entries are ignored."""

    if not isinstance(raw, list):
        return []
    result: list[tuple[str, str]] = []
    for item in raw[:6]:
        if not isinstance(item, dict):
            continue
        text = sanitize_text(str(item.get("text", "")), limit=64)
        url = str(item.get("url", "")).strip()
        if not text or not url or len(url) > 512:
            continue
        try:
            parsed = urlsplit(url)
        except ValueError:
            continue
        if parsed.scheme not in {"http", "https"} or not parsed.netloc:
            continue
        if parsed.username or parsed.password:
            continue
        result.append((text, url))
    return result


def resolve_cover(
    post: Post,
    *,
    global_cover: str | None,
    use_media_thumbnail: bool,
) -> str | None:
    if post.cover_file_id:
        return post.cover_file_id
    if global_cover:
        return global_cover
    if use_media_thumbnail:
        media: MediaAsset | None = post.media_asset
        if media is not None:
            return media.thumbnail_file_id
    return None
