from __future__ import annotations

from typing import TYPE_CHECKING, Any

from ..._constants import EMPTY_JSON
from ..._endpoints import Auth
from ..._internal._schemas import APIEnvelope
from .._base import BaseResource
from .._shared.auth import (
    build_tourist_headers,
    parse_login_and_apply_token,
)

if TYPE_CHECKING:
    from ..._async_client import AsyncClient
    from ..._internal._schemas.auth import AuthSession
else:
    AsyncClient = Any


class AsyncAuthResource(BaseResource[AsyncClient]):
    """Handles authentication for the async client (async).

    Accessible via ``client.auth``.
    """

    async def login(self, email: str, password: str) -> APIEnvelope[AuthSession]:
        """Log in with email and password.

        On success the client's auth token is updated automatically, so
        subsequent requests are authenticated without any extra steps.

        Args:
            email: Account email address.
            password: Account password.

        Returns:
            ``APIEnvelope[AuthSession]`` — ``.value.token`` is the auth
            token; ``.value.account`` contains basic account info.

        Raises:
            AuthError: If authentication fails.
            AccountNotFoundError: If no account with that email exists.
            InvalidPasswordError: If the password is incorrect.
            AccountBlockedError: If the account is blocked.

        Example:
            >>> session = await client.auth.login("user@example.com", "secret")
            >>> print(session.value.token)
        """
        env = await self._client.request_route(
            Auth.LOGIN,
            json={"email": email, "password": password},
        )
        return parse_login_and_apply_token(self._client, env)

    async def login_as_tourist(
        self, device_id: str | None = None
    ) -> APIEnvelope[AuthSession]:
        """Log in as a guest without credentials.

        On success the client's auth token is updated automatically.

        Args:
            device_id: Optional device identifier to associate with the
                guest session.

        Returns:
            ``APIEnvelope[AuthSession]`` — ``.value.token`` is the guest
            auth token.

        Example:
            >>> session = await client.auth.login_as_tourist()
            >>> print(session.value.token)
        """
        env = await self._client.request_route(
            Auth.LOGIN_TOURIST,
            json=EMPTY_JSON,
            headers=build_tourist_headers(self._client, device_id),
        )
        return parse_login_and_apply_token(self._client, env)

    async def logout(self) -> APIEnvelope[None]:
        """Log out the current session.

        Clears the client's auth token and notifies the server.

        Returns:
            ``APIEnvelope[None]`` — the server returns no data payload on
            success.

        Example:
            >>> await client.auth.logout()
        """
        self._client.set_token(None)
        return await self._client.request_route(Auth.LOGOUT)

    async def forgot_password(self, email: str) -> APIEnvelope[None]:
        """Send a password-reset email.

        Args:
            email: Email address of the account to reset.

        Returns:
            ``APIEnvelope[None]`` — the server returns no data payload on
            success.

        Example:
            >>> await client.auth.forgot_password("user@example.com")
        """
        return APIEnvelope[None].model_validate(
            await self._client.request_route(
                Auth.FORGOT_PASSWORD, json={"email": email}
            )
        )
