"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from .basesdk import BaseSDK
from .httpclient import AsyncHttpClient, ClientOwner, HttpClient, close_clients
from .sdkconfiguration import SDKConfiguration
from .utils.logger import Logger, get_default_logger
from .utils.retries import RetryConfig
from flexprice_py import models
from flexprice_py._hooks import SDKHooks
from flexprice_py.types import OptionalNullable, UNSET
import httpx
import importlib
import sys
from typing import Any, Callable, Optional, TYPE_CHECKING, Union, cast
import weakref

if TYPE_CHECKING:
    from flexprice_py.addons import Addons
    from flexprice_py.alerts import Alerts
    from flexprice_py.costs import Costs
    from flexprice_py.coupons import Coupons
    from flexprice_py.credit_grants import CreditGrants
    from flexprice_py.credit_notes import CreditNotes
    from flexprice_py.customers import Customers
    from flexprice_py.entitlements import Entitlements
    from flexprice_py.entity_integration_mappings import EntityIntegrationMappings
    from flexprice_py.environments import Environments
    from flexprice_py.events import Events
    from flexprice_py.features import Features
    from flexprice_py.groups import Groups
    from flexprice_py.integrations import Integrations
    from flexprice_py.invoices import Invoices
    from flexprice_py.payments import Payments
    from flexprice_py.plans import Plans
    from flexprice_py.price_units import PriceUnits
    from flexprice_py.prices import Prices
    from flexprice_py.rbac import Rbac
    from flexprice_py.scheduled_tasks import ScheduledTasks
    from flexprice_py.secrets import Secrets
    from flexprice_py.subscriptions import Subscriptions
    from flexprice_py.tasks import Tasks
    from flexprice_py.tax_associations import TaxAssociations
    from flexprice_py.tax_rates import TaxRates
    from flexprice_py.tenants import Tenants
    from flexprice_py.users import Users
    from flexprice_py.wallets import Wallets
    from flexprice_py.webhooks import Webhooks
    from flexprice_py.workflows import Workflows


class Flexprice(BaseSDK):
    r"""Flexprice API: Flexprice API provides billing, metering, and subscription management for SaaS and usage-based products. Use it to manage customers, plans, invoices, payments, usage events, and entitlements. Authenticate with an API key in the x-api-key header."""

    addons: "Addons"
    entitlements: "Entitlements"
    alerts: "Alerts"
    costs: "Costs"
    coupons: "Coupons"
    credit_grants: "CreditGrants"
    credit_notes: "CreditNotes"
    customers: "Customers"
    wallets: "Wallets"
    invoices: "Invoices"
    entity_integration_mappings: "EntityIntegrationMappings"
    environments: "Environments"
    events: "Events"
    features: "Features"
    groups: "Groups"
    payments: "Payments"
    plans: "Plans"
    prices: "Prices"
    price_units: "PriceUnits"
    rbac: "Rbac"
    secrets: "Secrets"
    integrations: "Integrations"
    subscriptions: "Subscriptions"
    tasks: "Tasks"
    scheduled_tasks: "ScheduledTasks"
    tax_associations: "TaxAssociations"
    tax_rates: "TaxRates"
    tenants: "Tenants"
    users: "Users"
    webhooks: "Webhooks"
    workflows: "Workflows"
    _sub_sdk_map = {
        "addons": ("flexprice_py.addons", "Addons"),
        "entitlements": ("flexprice_py.entitlements", "Entitlements"),
        "alerts": ("flexprice_py.alerts", "Alerts"),
        "costs": ("flexprice_py.costs", "Costs"),
        "coupons": ("flexprice_py.coupons", "Coupons"),
        "credit_grants": ("flexprice_py.credit_grants", "CreditGrants"),
        "credit_notes": ("flexprice_py.credit_notes", "CreditNotes"),
        "customers": ("flexprice_py.customers", "Customers"),
        "wallets": ("flexprice_py.wallets", "Wallets"),
        "invoices": ("flexprice_py.invoices", "Invoices"),
        "entity_integration_mappings": (
            "flexprice_py.entity_integration_mappings",
            "EntityIntegrationMappings",
        ),
        "environments": ("flexprice_py.environments", "Environments"),
        "events": ("flexprice_py.events", "Events"),
        "features": ("flexprice_py.features", "Features"),
        "groups": ("flexprice_py.groups", "Groups"),
        "payments": ("flexprice_py.payments", "Payments"),
        "plans": ("flexprice_py.plans", "Plans"),
        "prices": ("flexprice_py.prices", "Prices"),
        "price_units": ("flexprice_py.price_units", "PriceUnits"),
        "rbac": ("flexprice_py.rbac", "Rbac"),
        "secrets": ("flexprice_py.secrets", "Secrets"),
        "integrations": ("flexprice_py.integrations", "Integrations"),
        "subscriptions": ("flexprice_py.subscriptions", "Subscriptions"),
        "tasks": ("flexprice_py.tasks", "Tasks"),
        "scheduled_tasks": ("flexprice_py.scheduled_tasks", "ScheduledTasks"),
        "tax_associations": ("flexprice_py.tax_associations", "TaxAssociations"),
        "tax_rates": ("flexprice_py.tax_rates", "TaxRates"),
        "tenants": ("flexprice_py.tenants", "Tenants"),
        "users": ("flexprice_py.users", "Users"),
        "webhooks": ("flexprice_py.webhooks", "Webhooks"),
        "workflows": ("flexprice_py.workflows", "Workflows"),
    }

    def __init__(
        self,
        server_url: str,
        api_key_auth: Union[str, Callable[[], str]],
        client: Optional[HttpClient] = None,
        async_client: Optional[AsyncHttpClient] = None,
        retry_config: OptionalNullable[RetryConfig] = UNSET,
        timeout_ms: Optional[int] = None,
        debug_logger: Optional[Logger] = None,
    ) -> None:
        r"""Instantiates the SDK configuring it with the provided parameters.

        :param api_key_auth: The api_key_auth required for authentication
        :param server_idx: The index of the server to use for all methods
        :param server_url: The server URL to use for all methods
        :param url_params: Parameters to optionally template the server URL with
        :param client: The HTTP client to use for all synchronous methods
        :param async_client: The Async HTTP client to use for all asynchronous methods
        :param retry_config: The retry configuration to use for all supported methods
        :param timeout_ms: Optional request timeout applied to each operation in milliseconds
        """
        client_supplied = True
        if client is None:
            client = httpx.Client(follow_redirects=True)
            client_supplied = False

        assert issubclass(
            type(client), HttpClient
        ), "The provided client must implement the HttpClient protocol."

        async_client_supplied = True
        if async_client is None:
            async_client = httpx.AsyncClient(follow_redirects=True)
            async_client_supplied = False

        if debug_logger is None:
            debug_logger = get_default_logger()

        assert issubclass(
            type(async_client), AsyncHttpClient
        ), "The provided async_client must implement the AsyncHttpClient protocol."

        security: Any = None
        if callable(api_key_auth):
            # pylint: disable=unnecessary-lambda-assignment
            security = lambda: models.components.Security(api_key_auth=api_key_auth())
        else:
            security = models.components.Security(api_key_auth=api_key_auth)

        BaseSDK.__init__(
            self,
            SDKConfiguration(
                client=client,
                client_supplied=client_supplied,
                async_client=async_client,
                async_client_supplied=async_client_supplied,
                security=security,
                server_url=server_url,
                retry_config=retry_config,
                timeout_ms=timeout_ms,
                debug_logger=debug_logger,
            ),
            parent_ref=self,
        )

        hooks = SDKHooks()

        # pylint: disable=protected-access
        self.sdk_configuration.__dict__["_hooks"] = hooks

        self.sdk_configuration = hooks.sdk_init(self.sdk_configuration)

        weakref.finalize(
            self,
            close_clients,
            cast(ClientOwner, self.sdk_configuration),
            self.sdk_configuration.client,
            self.sdk_configuration.client_supplied,
            self.sdk_configuration.async_client,
            self.sdk_configuration.async_client_supplied,
        )

    def dynamic_import(self, modname, retries=3):
        for attempt in range(retries):
            try:
                return importlib.import_module(modname)
            except KeyError:
                # Clear any half-initialized module and retry
                sys.modules.pop(modname, None)
                if attempt == retries - 1:
                    break
        raise KeyError(f"Failed to import module '{modname}' after {retries} attempts")

    def __getattr__(self, name: str):
        if name in self._sub_sdk_map:
            module_path, class_name = self._sub_sdk_map[name]
            try:
                module = self.dynamic_import(module_path)
                klass = getattr(module, class_name)
                instance = klass(self.sdk_configuration, parent_ref=self)
                setattr(self, name, instance)
                return instance
            except ImportError as e:
                raise AttributeError(
                    f"Failed to import module {module_path} for attribute {name}: {e}"
                ) from e
            except AttributeError as e:
                raise AttributeError(
                    f"Failed to find class {class_name} in module {module_path} for attribute {name}: {e}"
                ) from e

        raise AttributeError(
            f"'{type(self).__name__}' object has no attribute '{name}'"
        )

    def __dir__(self):
        default_attrs = list(super().__dir__())
        lazy_attrs = list(self._sub_sdk_map.keys())
        return sorted(list(set(default_attrs + lazy_attrs)))

    def __enter__(self):
        return self

    async def __aenter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if (
            self.sdk_configuration.client is not None
            and not self.sdk_configuration.client_supplied
        ):
            self.sdk_configuration.client.close()
        self.sdk_configuration.client = None

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        if (
            self.sdk_configuration.async_client is not None
            and not self.sdk_configuration.async_client_supplied
        ):
            await self.sdk_configuration.async_client.aclose()
        self.sdk_configuration.async_client = None
