"""Telegram authentication validation for cabinet."""

import hashlib
import hmac
import json
from datetime import UTC, datetime
from typing import Any
from urllib.parse import parse_qsl, unquote

from app.config import settings


def validate_telegram_login_widget(data: dict[str, Any], max_age_seconds: int = 86400) -> bool:
    """
    Validate Telegram Login Widget data.

    https://core.telegram.org/widgets/login#checking-authorization

    Args:
        data: Dictionary with Telegram login data (id, first_name, auth_date, hash, etc.)
        max_age_seconds: Maximum allowed age of auth_date (default 24 hours)

    Returns:
        True if data is valid, False otherwise
    """
    auth_data = data.copy()
    check_hash = auth_data.pop('hash', None)

    if not check_hash:
        return False

    # Check auth_date is not too old
    auth_date = auth_data.get('auth_date')
    if auth_date:
        try:
            # Use UTC timestamp to avoid timezone issues
            auth_time = datetime.fromtimestamp(int(auth_date), tz=UTC)
            age = (datetime.now(UTC) - auth_time).total_seconds()
            if age > max_age_seconds:
                return False
        except (ValueError, TypeError, OSError):
            return False

    # Build data-check-string (sorted key=value pairs, newline-separated)
    data_check_arr = [f'{k}={v}' for k, v in sorted(auth_data.items()) if v is not None]
    data_check_string = '\n'.join(data_check_arr)

    # Create secret key from bot token using SHA256
    bot_token = settings.BOT_TOKEN
    secret_key = hashlib.sha256(bot_token.encode()).digest()

    # Calculate expected hash
    calculated_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest()

    return hmac.compare_digest(calculated_hash, check_hash)


def validate_telegram_init_data(init_data: str, max_age_seconds: int = 86400) -> dict[str, Any] | None:
    """
    Validate Telegram WebApp initData.

    https://core.telegram.org/bots/webapps#validating-data-received-via-the-mini-app

    Args:
        init_data: Raw initData string from Telegram WebApp
        max_age_seconds: Maximum allowed age of auth_date (default 24 hours)

    Returns:
        Parsed user data dict if valid, None otherwise
    """
    try:
        # Parse the init_data string
        parsed = dict(parse_qsl(init_data, keep_blank_values=True))

        received_hash = parsed.pop('hash', None)
        if not received_hash:
            return None

        # Check auth_date is not too old
        auth_date = parsed.get('auth_date')
        if auth_date:
            try:
                # Use UTC timestamp to avoid timezone issues
                auth_time = datetime.fromtimestamp(int(auth_date), tz=UTC)
                age = (datetime.now(UTC) - auth_time).total_seconds()
                if age > max_age_seconds:
                    return None
            except (ValueError, TypeError, OSError):
                return None

        # Build data-check-string
        data_check_arr = [f'{k}={v}' for k, v in sorted(parsed.items())]
        data_check_string = '\n'.join(data_check_arr)

        # Create secret key: HMAC_SHA256(bot_token, "WebAppData")
        bot_token = settings.BOT_TOKEN
        secret_key = hmac.new(b'WebAppData', bot_token.encode(), hashlib.sha256).digest()

        # Calculate expected hash
        calculated_hash = hmac.new(secret_key, data_check_string.encode(), hashlib.sha256).hexdigest()

        if not hmac.compare_digest(calculated_hash, received_hash):
            return None

        # Parse user data from the validated data
        user_data_str = parsed.get('user')
        if user_data_str:
            user_data = json.loads(unquote(user_data_str))
            return user_data

        return parsed

    except (ValueError, TypeError, json.JSONDecodeError):
        return None


def extract_telegram_user_from_init_data(init_data: str) -> dict[str, Any] | None:
    """
    Extract and validate user info from Telegram WebApp initData.

    Args:
        init_data: Raw initData string from Telegram WebApp

    Returns:
        User data dict with id, first_name, last_name, username, etc. or None if invalid
    """
    return validate_telegram_init_data(init_data)
