"""
Утилиты для работы с реферальными ссылками.

Генерация и декодирование происходит локально,
без обращения к GlobalAuth API.

Формат кода (бинарный, base64url):
    referral: тип(1) + uuid(16) + service(N) → ref_xxx
    event:    тип(1) + service_len(1) + service(N) + event_id(N) → evt_xxx

Example:
    from opengater_globalauth_client.utils import generate_referral_link

    link = generate_referral_link(
        user_id="4a86a7f5-99f0-42c1-8f34-5410be276d51",
        service_slug="opengater",
        public_url="https://lk.bot.eutochkin.com/user/balance",
        referral_param="referral",
    )
    # https://lk.bot.eutochkin.com/user/balance?referral=ref_AUqGp...
"""
import base64
import struct
from uuid import UUID

# Типы кодов
_TYPE_REFERRAL = 0x01
_TYPE_EVENT = 0x02


def _b64_encode(data: bytes) -> str:
    """base64url encode без padding"""
    return base64.urlsafe_b64encode(data).decode().rstrip("=")


def _b64_decode(encoded: str) -> bytes | None:
    """base64url decode с восстановлением padding"""
    try:
        padding = 4 - len(encoded) % 4
        if padding != 4:
            encoded += "=" * padding
        return base64.urlsafe_b64decode(encoded)
    except Exception:
        return None


def generate_referral_code(user_id: str, service_slug: str) -> str:
    """
    Генерация реферального кода.

    Args:
        user_id: UUID пользователя (globalauth_id)
        service_slug: Slug сервиса (например "opengater")

    Returns:
        Код вида ref_AUqGp_WZ8...
    """
    uid = UUID(str(user_id))
    data = struct.pack("B", _TYPE_REFERRAL) + uid.bytes + service_slug.encode("utf-8")
    return "ref_" + _b64_encode(data)


def generate_event_code(event_id: str, service_slug: str) -> str:
    """
    Генерация кода события.

    Args:
        event_id: ID события
        service_slug: Slug сервиса

    Returns:
        Код вида evt_AgVvcGVu...
    """
    service_bytes = service_slug.encode("utf-8")
    event_bytes = event_id.encode("utf-8")
    data = (
            struct.pack("BB", _TYPE_EVENT, len(service_bytes))
            + service_bytes
            + event_bytes
    )
    return "evt_" + _b64_encode(data)


def generate_referral_link(
        user_id: str,
        service_slug: str,
        public_url: str,
        referral_param: str = "referral",
) -> str:
    """
    Генерация полной реферальной ссылки.

    Args:
        user_id: UUID пользователя (globalauth_id)
        service_slug: Slug сервиса
        public_url: Базовый URL (например https://lk.bot.eutochkin.com/user/balance)
        referral_param: Имя GET-параметра (например "referral")

    Returns:
        https://lk.bot.eutochkin.com/user/balance?referral=ref_xxx
    """
    code = generate_referral_code(user_id, service_slug)
    separator = "&" if "?" in public_url else "?"
    return f"{public_url}{separator}{referral_param}={code}"


def generate_event_link(
        event_id: str,
        service_slug: str,
        public_url: str,
        referral_param: str = "referral",
) -> str:
    """
    Генерация полной ссылки события.

    Args:
        event_id: ID события
        service_slug: Slug сервиса
        public_url: Базовый URL
        referral_param: Имя GET-параметра

    Returns:
        https://lk.bot.eutochkin.com/user/balance?referral=evt_xxx
    """
    code = generate_event_code(event_id, service_slug)
    separator = "&" if "?" in public_url else "?"
    return f"{public_url}{separator}{referral_param}={code}"


def decode_code(code: str) -> dict | None:
    """
    Декодирование реферального кода или кода события.

    Args:
        code: Код из ссылки (ref_xxx или evt_xxx)

    Returns:
        {"type": "referral", "inviter_id": "uuid", "service_slug": "..."} или
        {"type": "event", "event_id": "...", "service_slug": "..."} или
        None
    """
    if code.startswith("ref_"):
        data = _b64_decode(code[4:])
        if not data or len(data) < 17:
            return None

        code_type = data[0]
        if code_type != _TYPE_REFERRAL:
            return None

        uid = UUID(bytes=data[1:17])
        service_slug = data[17:].decode("utf-8") if len(data) > 17 else None

        result = {"type": "referral", "inviter_id": str(uid)}
        if service_slug:
            result["service_slug"] = service_slug
        return result

    elif code.startswith("evt_"):
        data = _b64_decode(code[4:])
        if not data or len(data) < 3:
            return None

        code_type = data[0]
        if code_type != _TYPE_EVENT:
            return None

        service_len = data[1]
        if len(data) < 2 + service_len + 1:
            return None

        service_slug = data[2:2 + service_len].decode("utf-8")
        event_id = data[2 + service_len:].decode("utf-8")

        return {
            "type": "event",
            "event_id": event_id,
            "service_slug": service_slug,
        }

    return None
