"""Input validation and Persian-friendly formatting helpers."""

from __future__ import annotations

import re
from datetime import UTC, datetime
from urllib.parse import urlsplit
from zoneinfo import ZoneInfo

from app.errors import ValidationError

_PERSIAN_DIGITS = str.maketrans("۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩", "01234567890123456789")
_CHAT_ID_RE = re.compile(r"^-?\d{5,20}$")


def normalize_digits(value: str) -> str:
    return value.translate(_PERSIAN_DIGITS)


def parse_int(value: str, *, name: str = "عدد", minimum: int | None = None) -> int:
    text = normalize_digits(str(value).strip()).replace(",", "").replace("،", "")
    try:
        number = int(text)
    except ValueError as exc:
        raise ValidationError(f"{name} باید یک عدد صحیح باشد.") from exc
    if minimum is not None and number < minimum:
        raise ValidationError(f"{name} باید بزرگ‌تر یا مساوی {minimum} باشد.")
    return number


def parse_chat_id(value: str) -> int:
    text = normalize_digits(str(value).strip())
    if not _CHAT_ID_RE.fullmatch(text):
        raise ValidationError(
            "شناسه چت معتبر نیست. شناسه عددی مانند -1001234567890 را وارد کنید."
        )
    number = int(text)
    if number == 0:
        raise ValidationError("شناسه چت نمی‌تواند صفر باشد.")
    return number


def parse_telegram_user_id(value: str) -> int:
    number = parse_int(value, name="شناسه کاربر", minimum=1)
    if number > 9_999_999_999_999:
        raise ValidationError("شناسه کاربر خارج از محدوده مجاز است.")
    return number


def parse_duration_seconds(value: str) -> int:
    text = normalize_digits(str(value).strip()).lower().replace(" ", "")
    multiplier = 1
    for suffix, factor in (
        ("ساعت", 3600),
        ("دقیقه", 60),
        ("ثانیه", 1),
        ("hour", 3600),
        ("hours", 3600),
        ("minute", 60),
        ("minutes", 60),
        ("second", 1),
        ("seconds", 1),
        ("h", 3600),
        ("m", 60),
        ("s", 1),
        ("د", 60),
        ("س", 1),
    ):
        if text.endswith(suffix):
            text = text[: -len(suffix)]
            multiplier = factor
            break
    number = parse_int(text, name="مدت", minimum=1)
    seconds = number * multiplier
    if seconds > 7 * 24 * 3600:
        raise ValidationError("حداکثر مدت حذف خودکار ۷ روز است.")
    return seconds


def parse_local_datetime(value: str, tz: ZoneInfo) -> datetime:
    text = normalize_digits(str(value).strip()).replace("T", " ")
    text = re.sub(r"\s+", " ", text)
    for fmt in ("%Y-%m-%d %H:%M", "%Y/%m/%d %H:%M", "%Y-%m-%d %H:%M:%S"):
        try:
            naive = datetime.strptime(text, fmt)
        except ValueError:
            continue
        local = naive.replace(tzinfo=tz)
        return local.astimezone(UTC)
    raise ValidationError("زمان معتبر نیست. قالب درست: 2026-12-31 21:30")


def format_local(value: datetime | None, tz: ZoneInfo, *, empty: str = "—") -> str:
    if value is None:
        return empty
    if value.tzinfo is None:
        value = value.replace(tzinfo=UTC)
    return value.astimezone(tz).strftime("%Y-%m-%d %H:%M")


def format_duration(seconds: int | None) -> str:
    if not seconds or seconds <= 0:
        return "بدون حذف خودکار"
    if seconds % 3600 == 0:
        return f"{seconds // 3600} ساعت"
    if seconds % 60 == 0:
        return f"{seconds // 60} دقیقه"
    return f"{seconds} ثانیه"


def validate_http_url(value: str) -> str:
    text = str(value).strip()
    if len(text) > 512:
        raise ValidationError("طول لینک بیش از حد مجاز است.")
    try:
        parsed = urlsplit(text)
    except ValueError as exc:
        raise ValidationError("لینک معتبر نیست.") from exc
    if parsed.scheme not in {"http", "https"} or not parsed.netloc:
        raise ValidationError("لینک باید با http:// یا https:// شروع شود.")
    if parsed.username or parsed.password:
        raise ValidationError("لینک نباید نام کاربری یا رمز داشته باشد.")
    if parsed.hostname in {"localhost", "127.0.0.1", "::1"}:
        raise ValidationError("لینک محلی برای دکمه پست مجاز نیست.")
    return text


def validate_link_template(value: str) -> str:
    """Validate a deep-link template without requiring a live bot username."""

    text = str(value).strip()
    if len(text) > 512:
        raise ValidationError("طول قالب لینک بیش از حد مجاز است.")
    if "{token}" not in text:
        raise ValidationError("قالب لینک باید شامل {token} باشد.")
    validate_http_url(
        text.replace("{bot_username}", "example_bot").replace("{token}", "example-token")
    )
    return text


def validate_buttons_json(raw: str) -> list[dict[str, str]]:
    import json

    try:
        data = json.loads(raw)
    except ValueError as exc:
        raise ValidationError("قالب دکمه‌ها باید JSON باشد.") from exc
    if not isinstance(data, list) or len(data) > 6:
        raise ValidationError("دکمه‌ها باید آرایه‌ای با حداکثر ۶ عضو باشند.")
    result: list[dict[str, str]] = []
    for item in data:
        if not isinstance(item, dict):
            raise ValidationError("هر دکمه باید شیء شامل text و url باشد.")
        text = str(item.get("text", "")).strip()
        url = str(item.get("url", "")).strip()
        if not text or len(text) > 64:
            raise ValidationError("متن هر دکمه باید بین ۱ تا ۶۴ کاراکتر باشد.")
        result.append({"text": text, "url": validate_http_url(url)})
    return result


def mask_token(token: str) -> str:
    if len(token) <= 8:
        return "***"
    return f"{token[:4]}…{token[-4:]}"
