"""
Token types for the 42 API OAuth2 flow.
"""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from typing import TYPE_CHECKING

from dateutil.relativedelta import relativedelta
from pytz import timezone


if TYPE_CHECKING:
    import httpx


@dataclass
class Tokens:
    """
    Container for 42 API authentication tokens.

    Attributes:
        access_token: The OAuth2 access token for API requests.
        refresh_token: Optional refresh token for obtaining new access tokens.
        token_type: The type of token (typically "bearer").
        scope: The scope of access granted by the token.
        created_at: Unix timestamp when the token was created.
        secret_valid_until: Unix timestamp until which the secret is valid.
    """

    access_token: str
    refresh_token: str | None = None
    token_type: str = "bearer"
    scope: str = "public"
    created_at: int | None = None
    secret_valid_until: int | None = None

    def is_expired(self) -> bool:
        """
        Check if the token has expired.

        Returns:
            True if the token has expired, False otherwise.
        """
        if self.created_at is None:
            return True

        token_created = datetime.fromtimestamp(self.created_at, tz=timezone("UTC"))
        expiration_time = token_created + relativedelta(hours=2)

        return datetime.now(timezone("UTC")) >= expiration_time


def parse_token_response(response: httpx.Response) -> Tokens:
    """
    Parse a token response from the 42 OAuth endpoint into a Tokens object.

    Args:
        response: The HTTP response from the OAuth endpoint.

    Returns:
        Tokens object containing authentication tokens.
    """
    body = response.json()
    return Tokens(
        access_token=body["access_token"],
        refresh_token=body.get("refresh_token"),
        token_type=body["token_type"],
        scope=body["scope"],
        created_at=body["created_at"],
        secret_valid_until=body.get("secret_valid_until", 0),
    )
