"""
Утилиты для работы с информацией о пользователях
"""
from typing import Optional, Union
from enum import Enum

from aiogram.types import Message, CallbackQuery, User, InlineQuery, ChatMemberUpdated

__all__ = (
    'get_user_display_name',
    'get_user_mention',
    'get_user_id',
    'username',
    'format_user',
    'UserFormat',
    'is_bot',
    'has_username',
    'is_premium',
    'get_language_code',
    'compare_users',
    'get_user_info_dict'
)


class UserFormat(str, Enum):
    """Форматы отображения пользователя"""
    USERNAME = 'username'  # @username или @id123
    FULL_NAME = 'full_name'  # Имя Фамилия
    MENTION = 'mention'  # HTML mention
    MENTION_MARKDOWN = 'markdown'  # Markdown mention
    FIRST_NAME = 'first_name'  # Только имя
    ID_ONLY = 'id'  # Только ID
    DETAILED = 'detailed'  # @username (Имя Фамилия, ID: 123)


# Тип для всех событий с пользователем
EventType = Union[Message, CallbackQuery, InlineQuery, ChatMemberUpdated]


def _extract_user(event: EventType) -> Optional[User]:
    """
    Извлекает объект User из события.

    Args:
        event: Объект события

    Returns:
        User или None
    """
    if isinstance(event, (Message, CallbackQuery, InlineQuery)):
        return event.from_user
    elif isinstance(event, ChatMemberUpdated):
        return event.from_user or event.new_chat_member.user

    return None


def get_user_display_name(
        event: EventType,
        default: str = "Unknown User"
) -> str:
    """
    Возвращает отображаемое имя пользователя (Full Name).

    Args:
        event: Объект события (Message, CallbackQuery, и т.д.)
        default: Значение по умолчанию если пользователь не найден

    Returns:
        str: Полное имя пользователя

    Example:
        >> get_user_display_name(message)
        'John Doe'
        >> get_user_display_name(message)
        'John'  # Если нет фамилии
    """
    user = _extract_user(event)

    if not user:
        return default

    # Полное имя (приоритет)
    if user.full_name:
        return user.full_name

    # Только имя
    if user.first_name:
        return user.first_name

    # Username как запасной вариант
    if user.username:
        return f"@{user.username}"

    # ID как последний вариант
    return f"User {user.id}"


def get_user_mention(
        event: EventType,
        parse_mode: str = 'HTML',
        show_username: bool = False
) -> str:
    """
    Возвращает упоминание пользователя (кликабельное).

    Args:
        event: Объект события
        parse_mode: Режим парсинга ('HTML' или 'Markdown')
        show_username: Показывать username вместо имени

    Returns:
        str: HTML/Markdown упоминание

    Example:
        >> get_user_mention(message)
        '<a href="tg://user?id=123456789">John Doe</a>'

        >> get_user_mention(message, parse_mode='Markdown')
        '[John Doe](tg://user?id=123456789)'

        >> get_user_mention(message, show_username=True)
        '<a href="tg://user?id=123456789">@johndoe</a>'
    """
    user = _extract_user(event)

    if not user:
        return "Unknown User"

    # Определяем текст для отображения
    if show_username and user.username:
        display_text = f"@{user.username}"
    else:
        display_text = user.full_name or user.first_name or f"User {user.id}"

    # Формируем ссылку
    user_link = f"tg://user?id={user.id}"

    if parse_mode.upper() == 'HTML':
        return f'<a href="{user_link}">{display_text}</a>'
    elif parse_mode.upper() in ('MARKDOWN', 'MARKDOWNV2'):
        # Экранируем специальные символы для Markdown
        display_text = display_text.replace('[', '\\[').replace(']', '\\]')
        return f'[{display_text}]({user_link})'
    else:
        return display_text


def get_user_id(event: EventType) -> Optional[int]:
    """
    Возвращает ID пользователя.

    Args:
        event: Объект события

    Returns:
        int или None: ID пользователя

    Example:
        >> get_user_id(message)
        123456789
    """
    user = _extract_user(event)
    return user.id if user else None


def username(
        event: EventType,
        with_at: bool = True,
        fallback_to_id: bool = True
) -> str:
    """
    Возвращает username пользователя или ID если username отсутствует.

    Это основная функция для получения идентификатора пользователя
    в формате @username или @id123.

    Args:
        event: Объект события (Message, CallbackQuery, и т.д.)
        with_at: Добавлять @ в начало
        fallback_to_id: Использовать ID если нет username

    Returns:
        str: Username или ID пользователя

    Raises:
        ValueError: Если информация о пользователе отсутствует

    Example:
        >> username(message)
        '@johndoe'

        >> username(message)  # Нет username
        '@123456789'

        >> username(message, with_at=False)
        'johndoe'

        >> username(message, fallback_to_id=False)
        ''  # Если нет username
    """
    user = _extract_user(event)

    if not user:
        raise ValueError("Информация о пользователе отсутствует в событии")

    # Если есть username
    if user.username:
        return f"@{user.username}" if with_at else user.username

    # Fallback на ID
    if fallback_to_id:
        return f"@{user.id}" if with_at else str(user.id)

    # Если ничего нет
    return ""


def format_user(
        event: EventType,
        format_type: UserFormat = UserFormat.USERNAME,
        default: str = "@System"
) -> str:
    """
    Универсальная функция форматирования пользователя.

    Args:
        event: Объект события
        format_type: Тип форматирования (из enum UserFormat)
        default: Значение по умолчанию

    Returns:
        str: Отформатированная информация о пользователе

    Example:
        >> format_user(message, UserFormat.USERNAME)
        '@johndoe'

        >> format_user(message, UserFormat.FULL_NAME)
        'John Doe'

        >> format_user(message, UserFormat.MENTION)
        '<a href="tg://user?id=123">John Doe</a>'

        >> format_user(message, UserFormat.DETAILED)
        '@johndoe (John Doe, ID: 123456789)'
    """
    user = _extract_user(event)

    if not user:
        return default

    # USERNAME: @username или @id
    if format_type == UserFormat.USERNAME:
        if user.username:
            return f"@{user.username}"
        return f"@{user.id}"

    # FULL_NAME: Имя Фамилия
    elif format_type == UserFormat.FULL_NAME:
        return user.full_name or user.first_name or f"User {user.id}"

    # MENTION: HTML упоминание
    elif format_type == UserFormat.MENTION:
        display = user.full_name or user.first_name or f"User {user.id}"
        return f'<a href="tg://user?id={user.id}">{display}</a>'

    # MENTION_MARKDOWN: Markdown упоминание
    elif format_type == UserFormat.MENTION_MARKDOWN:
        display = user.full_name or user.first_name or f"User {user.id}"
        display = display.replace('[', '\\[').replace(']', '\\]')
        return f'[{display}](tg://user?id={user.id})'

    # FIRST_NAME: Только имя
    elif format_type == UserFormat.FIRST_NAME:
        return user.first_name or f"User {user.id}"

    # ID_ONLY: Только ID
    elif format_type == UserFormat.ID_ONLY:
        return str(user.id)

    # DETAILED: Подробная информация
    elif format_type == UserFormat.DETAILED:
        parts = []

        # Username
        if user.username:
            parts.append(f"@{user.username}")

        # Full name
        if user.full_name:
            parts.append(f"({user.full_name}")
        elif user.first_name:
            parts.append(f"({user.first_name}")

        # ID
        parts.append(f"ID: {user.id})")

        return ' '.join(parts) if parts else f"User {user.id}"

    # По умолчанию
    return default


# ================= ДОПОЛНИТЕЛЬНЫЕ УТИЛИТЫ =================

def is_bot(event: EventType) -> bool:
    """
    Проверяет, является ли пользователь ботом.

    Args:
        event: Объект события

    Returns:
        bool: True если бот
    """
    user = _extract_user(event)
    return user.is_bot if user else False


def has_username(event: EventType) -> bool:
    """
    Проверяет, есть ли у пользователя username.

    Args:
        event: Объект события

    Returns:
        bool: True если есть username
    """
    user = _extract_user(event)
    return bool(user and user.username)


def is_premium(event: EventType) -> bool:
    """
    Проверяет, есть ли у пользователя Telegram Premium.

    Args:
        event: Объект события

    Returns:
        bool: True если Premium
    """
    user = _extract_user(event)
    return user.is_premium if user else False


def get_language_code(event: EventType) -> Optional[str]:
    """
    Возвращает код языка пользователя.

    Args:
        event: Объект события

    Returns:
        Optional[str]: Код языка ('ru', 'en', и т.д.)
    """
    user = _extract_user(event)
    return user.language_code if user else None


def compare_users(event1: EventType, event2: EventType) -> bool:
    """
    Сравнивает двух пользователей по ID.

    Args:
        event1: Первое событие
        event2: Второе событие

    Returns:
        bool: True если это один и тот же пользователь
    """
    user1 = _extract_user(event1)
    user2 = _extract_user(event2)

    if not user1 or not user2:
        return False

    return user1.id == user2.id


def get_user_info_dict(event: EventType) -> dict:
    """
    Возвращает всю информацию о пользователе в виде словаря.

    Args:
        event: Объект события

    Returns:
        dict: Словарь с информацией о пользователе
    """
    user = _extract_user(event)

    if not user:
        return {}

    return {
        'id': user.id,
        'username': user.username,
        'first_name': user.first_name,
        'last_name': user.last_name,
        'full_name': user.full_name,
        'is_bot': user.is_bot,
        'is_premium': user.is_premium,
        'language_code': user.language_code,
        'mention': get_user_mention(event),
        'display_name': get_user_display_name(event)
    }
