"""Main client for the Fastn Auth SDK."""

from typing import Optional, Union

import aiohttp

from .errors import InvalidResponseError, NetworkError
from .session import AuthSession
from .types import Credentials, FastnAuthConfig, GetCredentialsOptions, InitOptions

DEFAULT_BASE_URL = "https://live.fastn.ai/api"


class FastnAuth:
    """Main client for the Fastn Auth SDK.

    Use this to initialize connector authentication flows.

    Example:
        ```python
        client = FastnAuth(
            space_id="your-space-id",
            api_key="your-api-key",
        )

        session = await client.initialize(
            connector_id="google-sheets",
        )

        # Redirect user to: session.redirect_url
        result = await session.wait_for_completion()
        ```
    """

    def __init__(
        self,
        space_id: str,
        api_key: Optional[str] = None,
        auth_token: Optional[str] = None,
        base_url: Optional[str] = None,
    ) -> None:
        """Create a new FastnAuth client.

        Args:
            space_id: The space/workspace ID.
            api_key: API key for authentication.
            auth_token: Auth token for authentication.
            base_url: Base URL for the Fastn API (optional).
        """
        if not api_key and not auth_token:
            raise ValueError("Either api_key or auth_token must be provided")
        self._config = FastnAuthConfig(
            space_id=space_id,
            api_key=api_key,
            auth_token=auth_token,
            base_url=base_url or DEFAULT_BASE_URL,
        )

    async def initialize(
        self,
        connector_id: str,
        org_id: Optional[str] = None,
        tenant_id: Optional[str] = None,
        connection_id: Optional[str] = None,
    ) -> AuthSession:
        """Initialize a connector authentication flow.

        Args:
            connector_id: The connector ID (e.g., "google-sheets", "salesforce").
            org_id: Organization ID (optional).
            tenant_id: Tenant ID (optional).
            connection_id: Connection instance ID (optional, defaults to "default").

        Returns:
            An AuthSession instance to manage the authentication flow.

        Raises:
            NetworkError: If the request fails.
            InvalidResponseError: If the response is invalid.
        """
        options = InitOptions(
            connector_id=connector_id,
            org_id=org_id,
            tenant_id=tenant_id,
            connection_id=connection_id,
        )

        actual_org_id = options.org_id or "community"
        url = f"{self._config.base_url}/connect/init/{actual_org_id}/{options.connector_id}"

        headers = self._build_headers(options)

        async with aiohttp.ClientSession() as session:
            async with session.post(url, headers=headers) as response:
                if not response.ok:
                    raise NetworkError(
                        f"Failed to initialize connection: {response.reason}",
                        status_code=response.status,
                    )

                data: dict = await response.json()

                if not data or "state" not in data:
                    raise InvalidResponseError("Invalid init response")

                state = data["state"]

                return AuthSession(
                    id=state,
                    state_key=state,
                    redirect_url=data.get("redirectUrl", ""),
                    base_url=self._config.base_url,
                    headers=headers,
                    connector_id=options.connector_id,
                    org_id=actual_org_id,
                )

    async def get_credentials(self, options: GetCredentialsOptions) -> Credentials:
        """Get credentials for a connector by creating a session with the given connectionId.

        Args:
            options: Options for fetching credentials.

        Returns:
            An AuthSession instance with the connectionId stored,
            use session.get_credentials() to fetch credentials.
        """
        headers = self._build_headers(options)
        session = AuthSession(
            id="",
            state_key="",
            redirect_url="",
            base_url=self._config.base_url or DEFAULT_BASE_URL,
            headers=headers,
            connector_id=options.connector_id,
            org_id=options.org_id or "community",
        )
        return await session.get_credentials()

    def _build_headers(
        self, options: Union[InitOptions, GetCredentialsOptions]
    ) -> dict[str, str]:
        """Build HTTP headers for the API request.

        Args:
            options: Initialization or credential options.

        Returns:
            Dictionary of HTTP headers.
        """
        headers: dict[str, str] = {
            "Content-Type": "application/json",
            "x-fastn-space-id": self._config.space_id,
        }

        if self._config.api_key:
            headers["x-fastn-api-key"] = self._config.api_key
        elif self._config.auth_token:
            headers["Authorization"] = f"Bearer {self._config.auth_token}"

        if options.tenant_id:
            headers["x-fastn-space-tenantid"] = options.tenant_id
        else:
            headers["x-fastn-space-tenantid"] = ""

        if options.connection_id:
            headers["x-fastn-space-connection-id"] = options.connection_id
        else:
            headers["x-fastn-space-connection-id"] = ""

        return headers
