"""Helper functions."""
from __future__ import annotations

import re
import time
from datetime import datetime, timedelta, timezone
from typing import Optional

from telegram import ChatMember, Message, User
from telegram.error import BadRequest
from telegram.helpers import mention_html

from bot.constants import E, PLACEHOLDERS

# ───────── Time parsing ─────────
TIME_RE = re.compile(r"(\d+)\s*([smhdw])", re.IGNORECASE)
TIME_UNITS = {
    "s": 1,
    "m": 60,
    "h": 3600,
    "d": 86400,
    "w": 604800,
}


def parse_time(text: str) -> Optional[int]:
    """Parse a duration string like '1h 30m' into seconds. Returns None if invalid."""
    if not text:
        return None
    if text.strip().lower() in ("0", "forever", "permanent"):
        return 0
    matches = TIME_RE.findall(text)
    if not matches:
        return None
    total = 0
    for value, unit in matches:
        total += int(value) * TIME_UNITS[unit.lower()]
    return total if total > 0 else None


def format_time(seconds: int) -> str:
    """Format seconds into a human-readable Persian string."""
    if seconds < 60:
        return f"{seconds} ثانیه"
    if seconds < 3600:
        return f"{seconds // 60} دقیقه"
    if seconds < 86400:
        return f"{seconds // 3600} ساعت"
    if seconds < 604800:
        return f"{seconds // 86400} روز"
    return f"{seconds // 604800} هفته"


# ───────── User extraction ─────────
async def extract_user(message: Message) -> Optional[User]:
    """Extract a target user from a message: reply, @username, or first arg as id."""
    if message.reply_to_message:
        return message.reply_to_message.from_user

    args = message.text.split() if message.text else []
    if len(args) < 2:
        return None

    target = args[1]
    # @username or username
    if target.startswith("@"):
        return target
    # numeric id
    if target.lstrip("-").isdigit():
        return int(target)
    return target


async def get_user_from_arg(bot, chat_id: int, arg: str) -> Optional[User]:
    """Resolve an arg string (id, @username, or name) into a User object."""
    if not arg:
        return None
    arg = arg.strip()
    if arg.startswith("@"):
        try:
            chat = await bot.get_chat(arg)
            return chat
        except BadRequest:
            return None
    if arg.lstrip("-").isdigit():
        try:
            return await bot.get_chat_member(chat_id, int(arg))
        except BadRequest:
            return None
    return None


# ───────── Formatting ─────────
def user_link(user: User, fallback: str = "کاربر") -> str:
    if not user:
        return fallback
    name = user.first_name or fallback
    return mention_html(user.id, name)


def user_link_raw(uid: int, name: str = "کاربر") -> str:
    """Build a mention HTML from raw uid + name (no User object needed)."""
    return mention_html(uid, name)


def user_id(user: User) -> int:
    return user.id if user else 0


def format_user_mention(user: User) -> str:
    if not user:
        return "ناشناس"
    name = user.first_name or ""
    if user.last_name:
        name = f"{name} {user.last_name}"
    return name.strip() or "ناشناس"


# ───────── Welcome / Goodbye formatting ─────────
def format_welcome_message(
    text: str, user: User, chat, member_count: Optional[int] = None
) -> str:
    """Replace placeholders in a welcome/goodbye message."""
    if not text:
        return text

    full_name = user.first_name or ""
    if user.last_name:
        full_name = f"{full_name} {user.last_name}"
    full_name = full_name.strip()

    replacements = {
        "{first}": user.first_name or "کاربر",
        "{last}": user.last_name or "",
        "{fullname}": full_name or "کاربر",
        "{username}": f"@{user.username}" if user.username else "بدون‌یوزرنیم",
        "{mention}": user_link(user),
        "{id}": str(user.id),
        "{chat}": chat.title if chat else "گروه",
        "{count}": str(member_count) if member_count else "?",
    }
    for k, v in replacements.items():
        text = text.replace(k, v)
    return text


# ───────── Detection helpers ─────────
URL_RE = re.compile(
    r"(?:(?:https?|ftp)://|www\.)[^\s<>\"']+|(?:t\.me/|telegram\.me/)[^\s<>\"']+",
    re.IGNORECASE,
)
INVITE_RE = re.compile(
    r"(?:t\.me/|telegram\.me/)(?:joinchat/|\+)?([A-Za-z0-9_\\-]+)",
    re.IGNORECASE,
)
MENTION_RE = re.compile(r"@[A-Za-z0-9_]{4,}")


def extract_links(text: str) -> list[str]:
    if not text:
        return []
    return URL_RE.findall(text)


def has_link(text: str) -> bool:
    if not text:
        return False
    return bool(URL_RE.search(text))


def is_persian_or_arabic(text: str) -> bool:
    if not text:
        return False
    return bool(re.search(r"[\u0600-\u06FF\u0750-\u077F\uFB50-\uFDFF\uFE70-\uFEFF]", text))


def is_english_only(text: str) -> bool:
    if not text:
        return False
    # Remove URLs, mentions, digits, and punctuation
    cleaned = re.sub(r"https?://\S+|www\.\S+|@\w+|[0-9\s\.,!?;:\-_]", "", text, flags=re.UNICODE)
    if not cleaned:
        return False
    return bool(re.search(r"[a-zA-Z]", cleaned)) and not is_persian_or_arabic(cleaned)


def is_emoji_only(text: str) -> bool:
    if not text:
        return False
    # Remove whitespace and common punctuation
    cleaned = re.sub(r"[\s\.\,\!\?\:\;\-\_]", "", text)
    if not cleaned:
        return False
    # Allow emojis and some special chars
    return not re.search(r"[a-zA-Z\u0600-\u06FF\u0750-\u077F]", cleaned)


# ───────── Target resolution ─────────
async def resolve_target(bot, message) -> Optional[int]:
    """Get user_id from reply or scan args (id/@username). Returns None if not found."""
    if message.reply_to_message and message.reply_to_message.from_user:
        return message.reply_to_message.from_user.id
    args = (message.text or "").split()
    if len(args) < 2:
        return None
    for arg in args[1:]:
        arg = arg.strip()
        if arg.startswith("@"):
            try:
                chat = await bot.get_chat(arg)
                return chat.id
            except BadRequest:
                continue
        if arg.lstrip("-").isdigit():
            return int(arg)
    return None


# ───────── Member checks ─────────
async def is_chat_admin(bot, chat_id: int, user_id: int) -> bool:
    try:
        member: ChatMember = await bot.get_chat_member(chat_id, user_id)
        return member.status in ("creator", "administrator")
    except BadRequest:
        return False


async def get_chat_member_count(bot, chat_id: int) -> Optional[int]:
    try:
        chat = await bot.get_chat(chat_id)
        return chat.member_count
    except BadRequest:
        return None


# ───────── Logging ─────────
async def log_action(
    bot,
    chat_id: int,
    log_channel_id: Optional[int],
    text: str,
) -> None:
    """Send an action log entry to a log channel if configured."""
    if not log_channel_id:
        return
    try:
        await bot.send_message(
            chat_id=log_channel_id,
            text=f"📍 <b>chat:</b> <code>{chat_id}</code>\n\n{text}",
            parse_mode="HTML",
            disable_web_page_preview=True,
        )
    except Exception as e:
        logging.getLogger(__name__).warning("Failed to send log action: %s", e)


# ───────── Text arg extraction ─────────
def get_text_args(update, context) -> str:
    """Get text after the command for English (/cmd args) or Persian (phrase args)."""
    if context.args:
        return " ".join(context.args)
    parts = (update.message.text or "").split(maxsplit=1)
    return parts[1] if len(parts) > 1 else ""


# ───────── Misc ─────────
def chunk_list(items: list, n: int):
    for i in range(0, len(items), n):
        yield items[i : i + n]


def timestamp_now() -> int:
    return int(time.time())


def format_timestamp(ts: int) -> str:
    dt = datetime.fromtimestamp(ts, tz=timezone.utc)
    return dt.strftime("%Y-%m-%d %H:%M:%S")
