import hashlib
import hmac
import time
from datetime import datetime, timedelta, timezone

import jwt
from django.conf import settings as django_settings

from moses.common import error_codes
from moses.common.exceptions import CustomAPIException, KwargsError
from moses.conf import settings as moses_settings


def verify_telegram_auth(data: dict, bot_token: str = None) -> dict:
    """
    Verify Telegram Login Widget data using HMAC-SHA-256.
    Returns the validated data dict.
    """
    if bot_token is None:
        bot_token = moses_settings.TELEGRAM_BOT_TOKEN
    if not bot_token:
        raise CustomAPIException({
            '': [KwargsError(code=error_codes.TELEGRAM_SIGN_IN_NOT_CONFIGURED)]
        })

    received_hash = data.get('hash', '')
    if not received_hash:
        raise CustomAPIException({
            'hash': [KwargsError(code=error_codes.INVALID_TELEGRAM_AUTH_DATA)]
        })

    # Build data_check_string: sorted key=value pairs excluding hash, joined by \n
    check_items = sorted(
        f"{k}={v}" for k, v in data.items() if k != 'hash'
    )
    data_check_string = '\n'.join(check_items)

    # secret_key = SHA256(bot_token)
    secret_key = hashlib.sha256(bot_token.encode('utf-8')).digest()

    # HMAC-SHA-256(secret_key, data_check_string)
    computed_hash = hmac.new(
        secret_key,
        data_check_string.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(computed_hash, received_hash):
        raise CustomAPIException({
            'hash': [KwargsError(code=error_codes.INVALID_TELEGRAM_AUTH_DATA)]
        })

    # Check auth_date is recent (within 1 day)
    auth_date = int(data.get('auth_date', 0))
    if time.time() - auth_date > 86400:
        raise CustomAPIException({
            'auth_date': [KwargsError(code=error_codes.TELEGRAM_AUTH_DATA_EXPIRED)]
        })

    return data


def create_telegram_temp_token(telegram_data: dict) -> str:
    """
    Create a short-lived JWT for completing Telegram registration.
    """
    expiry_minutes = moses_settings.TELEGRAM_AUTH_TEMP_TOKEN_EXPIRY_MINUTES
    payload = {
        'telegram_id': int(telegram_data['id']),
        'first_name': telegram_data.get('first_name', ''),
        'last_name': telegram_data.get('last_name', ''),
        'username': telegram_data.get('username', ''),
        'photo_url': telegram_data.get('photo_url', ''),
        'token_type': 'telegram_auth_temp',
        'exp': datetime.now(timezone.utc) + timedelta(minutes=expiry_minutes),
        'iat': datetime.now(timezone.utc),
    }
    return jwt.encode(payload, django_settings.SECRET_KEY, algorithm='HS256')


def decode_telegram_temp_token(token: str) -> dict:
    """
    Decode and validate the temporary Telegram auth token.
    """
    try:
        payload = jwt.decode(
            token,
            django_settings.SECRET_KEY,
            algorithms=['HS256']
        )
    except jwt.ExpiredSignatureError:
        raise CustomAPIException({
            'telegram_auth_token': [
                KwargsError(code=error_codes.TELEGRAM_AUTH_TEMP_TOKEN_EXPIRED)
            ]
        })
    except jwt.InvalidTokenError:
        raise CustomAPIException({
            'telegram_auth_token': [
                KwargsError(code=error_codes.INVALID_TELEGRAM_AUTH_TEMP_TOKEN)
            ]
        })

    if payload.get('token_type') != 'telegram_auth_temp':
        raise CustomAPIException({
            'telegram_auth_token': [
                KwargsError(code=error_codes.INVALID_TELEGRAM_AUTH_TEMP_TOKEN)
            ]
        })

    return payload
