"""CATAPA Python Client - Main Wrapper Class.

This module provides an ergonomic wrapper around the auto-generated CATAPA API client
with automatic OAuth2 authentication and token management.

Authors:
    Handrian Alandi (handrian.alandi@gdplabs.id)

References:
    NONE
"""

# Add generated package to path is now handled in __init__.py

import threading
from typing import Any, Dict, List

from catapa.auth.catapa_auth import CatapaAuth, CatapaConfig
from catapa.auto_refresh_api_client import AutoRefreshApiClient
from catapa.resource import Resource
from catapa.resource_registry import ROOT_RESOURCES
from openapi_client import Configuration

from .constant import USER_AGENT_KEY, USER_AGENT_VALUE


class Catapa(AutoRefreshApiClient):
    """Main CATAPA wrapper class providing access to all CATAPA APIs.

    Example:
        ```python
        from catapa_python import Catapa

        client = Catapa(
            tenant="your-tenant",
            client_id="your-client-id",
            client_secret="your-client-secret"
        )

        response = client.core.employees.list()
        employee = client.core.employees.retrieve(id="123")
        ```
    """

    def __init__(
        self, tenant: str, client_id: str, client_secret: str, base_url: str = "https://api.catapa.com"
    ) -> None:
        """Initialize the CATAPA client.

        Args:
            tenant (str): Your CATAPA tenant name.
            client_id (str): OAuth2 client ID.
            client_secret (str): OAuth2 client secret.
            base_url (str, optional): API base URL. Defaults to "https://api.catapa.com".
        """
        # Initialize attributes needed by __getattr__ BEFORE anything that might trigger it
        self._resource_cache: Dict[str, Resource] = {}
        self._resource_cache_lock = threading.Lock()
        self._attr_index: Dict[str, Any] = {node.attribute_name: node for node in ROOT_RESOURCES}

        self.config = CatapaConfig(tenant=tenant, client_id=client_id, client_secret=client_secret, base_url=base_url)

        self._auth = CatapaAuth(self.config)
        self._tenant_key = "Tenant"

        # Get initial access token
        access_token = self._auth.get_access_token()

        # Configure SDK
        configuration = Configuration(host=self.config.base_url)
        configuration.access_token = access_token

        # Initialize parent AutoRefreshApiClient with auto-refresh
        super().__init__(configuration, auth=self._auth)

        if not hasattr(self, "default_headers"):
            self.default_headers = {}
        tenant_value = getattr(self.config, "tenant", None)
        self.default_headers[self._tenant_key] = tenant_value
        self.default_headers[USER_AGENT_KEY] = USER_AGENT_VALUE

    def __getattr__(self, name: str) -> Any:
        """Dynamically access resources through root nodes."""
        node = self._attr_index.get(name)
        if node is None:
            raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
        if name not in self._resource_cache:
            with self._resource_cache_lock:
                if name not in self._resource_cache:
                    self._resource_cache[name] = Resource(node, self)
        return self._resource_cache[name]

    def __dir__(self) -> List[str]:
        """List available resources for IDE autocomplete support.

        Returns:
            List of all available attribute names from root resources
        """
        # Get standard class attributes
        base_attrs = list(object.__dir__(self))

        # Add all root resource attribute names
        resource_attrs = [node.attribute_name for node in ROOT_RESOURCES]

        return sorted(base_attrs + resource_attrs)

    def get_configuration(self) -> Configuration:
        """OpenAPI Configuration for advanced usage."""
        return self.configuration

    def refresh_auth(self) -> None:
        """Force refresh the authentication token.

        This is useful when you know the token has expired or you want to
        ensure you have a fresh token.
        """
        self._auth.refresh_token()
        # Update the configuration with the fresh token
        if self.configuration:
            self.configuration.access_token = self._auth.get_access_token()
