"""
Session management for the Tradier API.

This module provides the Session class which handles authentication
and HTTP requests to the Tradier API.
"""

from __future__ import annotations

from typing import Any

from httpx import AsyncClient, Client
from loguru import logger

from optrabot.broker.tradier import API_URL, SANDBOX_URL
from optrabot.broker.tradier.utils import validate_and_parse, validate_response


class Session:
    """
    A session for interacting with the Tradier API.

    The Session class manages authentication and provides methods for
    making HTTP requests to the Tradier API. It supports both synchronous
    and asynchronous operations.

    You can obtain an access token from your Tradier dashboard:
    https://dash.tradier.com/settings/api

    :param access_token: Your Tradier API access token.
    :param sandbox: Whether to use the sandbox (paper trading) environment.
                   Defaults to False (production).

    Example::

        # Production session
        session = Session("your-access-token")

        # Sandbox session for paper trading
        session = Session("your-sandbox-token", sandbox=True)
    """

    def __init__(
        self,
        access_token: str,
        sandbox: bool = False,
    ) -> None:
        #: The access token for API authentication
        self.access_token = access_token
        #: Whether this is a sandbox session
        self.is_sandbox = sandbox
        #: The base URL for API requests
        self.base_url = SANDBOX_URL if sandbox else API_URL

        # Setup HTTP headers
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Accept": "application/json",
        }

        #: Synchronous HTTP client
        self.sync_client = Client(
            base_url=self.base_url,
            headers=headers,
            timeout=30.0,
        )

        #: Asynchronous HTTP client
        self.async_client = AsyncClient(
            base_url=self.base_url,
            headers=headers,
            timeout=30.0,
        )

        logger.debug(
            "Session created for {} environment",
            "sandbox" if sandbox else "production",
        )

    def __repr__(self) -> str:
        env = "sandbox" if self.is_sandbox else "production"
        return f"Session(environment={env!r})"

    def __enter__(self) -> Session:
        return self

    def __exit__(self, *args: Any) -> None:
        self.close()

    async def __aenter__(self) -> Session:
        return self

    async def __aexit__(self, *args: Any) -> None:
        await self.a_close()

    def close(self) -> None:
        """Close the synchronous HTTP client."""
        self.sync_client.close()

    async def a_close(self) -> None:
        """Close the asynchronous HTTP client."""
        await self.async_client.aclose()

    # ========== Validation Methods ==========

    def validate(self) -> bool:
        """
        Validate the current session by fetching the user profile.

        :returns: True if the session is valid.
        :raises TradierAPIError: If the session is invalid.
        """
        response = self.sync_client.get("/user/profile")
        return response.status_code == 200

    async def a_validate(self) -> bool:
        """
        Validate the current session by fetching the user profile (async).

        :returns: True if the session is valid.
        :raises TradierAPIError: If the session is invalid.
        """
        response = await self.async_client.get("/user/profile")
        return response.status_code == 200

    # ========== Internal HTTP Methods ==========

    def _get(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make a GET request and return parsed JSON."""
        response = self.sync_client.get(url, **kwargs)
        return validate_and_parse(response)

    async def _a_get(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make an async GET request and return parsed JSON."""
        response = await self.async_client.get(url, **kwargs)
        return validate_and_parse(response)

    def _post(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make a POST request and return parsed JSON."""
        response = self.sync_client.post(url, **kwargs)
        return validate_and_parse(response)

    async def _a_post(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make an async POST request and return parsed JSON."""
        response = await self.async_client.post(url, **kwargs)
        return validate_and_parse(response)

    def _put(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make a PUT request and return parsed JSON."""
        response = self.sync_client.put(url, **kwargs)
        return validate_and_parse(response)

    async def _a_put(self, url: str, **kwargs: Any) -> dict[str, Any]:
        """Make an async PUT request and return parsed JSON."""
        response = await self.async_client.put(url, **kwargs)
        return validate_and_parse(response)

    def _delete(self, url: str, **kwargs: Any) -> None:
        """Make a DELETE request."""
        response = self.sync_client.delete(url, **kwargs)
        validate_response(response)

    async def _a_delete(self, url: str, **kwargs: Any) -> None:
        """Make an async DELETE request."""
        response = await self.async_client.delete(url, **kwargs)
        validate_response(response)
