"""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
import httpx
import importlib
from moovio_sdk import utils
from moovio_sdk._hooks import SDKHooks
from moovio_sdk.models import components, internal
from moovio_sdk.types import OptionalNullable, UNSET
import sys
from typing import Callable, Dict, Optional, TYPE_CHECKING, Union, cast
import weakref

if TYPE_CHECKING:
    from moovio_sdk.account_terminal_applications import AccountTerminalApplications
    from moovio_sdk.accounts import Accounts
    from moovio_sdk.adjustments import Adjustments
    from moovio_sdk.apple_pay import ApplePay
    from moovio_sdk.authentication import Authentication
    from moovio_sdk.avatars import Avatars
    from moovio_sdk.bank_accounts import BankAccounts
    from moovio_sdk.branding import Branding
    from moovio_sdk.capabilities import Capabilities
    from moovio_sdk.card_issuing import CardIssuing
    from moovio_sdk.cards import Cards
    from moovio_sdk.disputes import Disputes
    from moovio_sdk.end_to_end_encryption import EndToEndEncryption
    from moovio_sdk.enriched_address import EnrichedAddress
    from moovio_sdk.enriched_profile import EnrichedProfile
    from moovio_sdk.fee_plans import FeePlans
    from moovio_sdk.files import Files
    from moovio_sdk.images import Images
    from moovio_sdk.industries import Industries
    from moovio_sdk.institutions import Institutions
    from moovio_sdk.invoices import Invoices
    from moovio_sdk.issuing_transactions import IssuingTransactions
    from moovio_sdk.onboarding import Onboarding
    from moovio_sdk.payment_links import PaymentLinks
    from moovio_sdk.payment_methods import PaymentMethods
    from moovio_sdk.ping import Ping
    from moovio_sdk.products import Products
    from moovio_sdk.receipts import Receipts
    from moovio_sdk.representatives import Representatives
    from moovio_sdk.scheduling import Scheduling
    from moovio_sdk.statements import Statements
    from moovio_sdk.support import Support
    from moovio_sdk.sweeps import Sweeps
    from moovio_sdk.terminal_applications import TerminalApplications
    from moovio_sdk.transfers import Transfers
    from moovio_sdk.underwriting import Underwriting
    from moovio_sdk.wallet_transactions import WalletTransactions
    from moovio_sdk.wallets import Wallets
    from moovio_sdk.webhooks import Webhooks


class Moov(BaseSDK):
    r"""Moov API: Moov is a platform that enables developers to integrate all aspects of money movement with ease and speed.
    The Moov API makes it simple for platforms to send, receive, and store money. Our API is based upon REST
    principles, returns JSON responses, and uses standard HTTP response codes. To learn more about how Moov
    works at a high level, read our [concepts](https://docs.moov.io/guides/get-started/glossary/) guide.
    https://docs.moov.io/ - Moov Guides and API Documentation
    """

    accounts: "Accounts"
    adjustments: "Adjustments"
    apple_pay: "ApplePay"
    bank_accounts: "BankAccounts"
    branding: "Branding"
    capabilities: "Capabilities"
    cards: "Cards"
    disputes: "Disputes"
    fee_plans: "FeePlans"
    files: "Files"
    images: "Images"
    invoices: "Invoices"
    payment_links: "PaymentLinks"
    payment_methods: "PaymentMethods"
    products: "Products"
    representatives: "Representatives"
    scheduling: "Scheduling"
    statements: "Statements"
    sweeps: "Sweeps"
    account_terminal_applications: "AccountTerminalApplications"
    support: "Support"
    transfers: "Transfers"
    underwriting: "Underwriting"
    wallets: "Wallets"
    wallet_transactions: "WalletTransactions"
    avatars: "Avatars"
    end_to_end_encryption: "EndToEndEncryption"
    enriched_address: "EnrichedAddress"
    enriched_profile: "EnrichedProfile"
    webhooks: "Webhooks"
    industries: "Industries"
    institutions: "Institutions"
    issuing_transactions: "IssuingTransactions"
    card_issuing: "CardIssuing"
    authentication: "Authentication"
    onboarding: "Onboarding"
    ping: "Ping"
    receipts: "Receipts"
    terminal_applications: "TerminalApplications"
    _sub_sdk_map = {
        "accounts": ("moovio_sdk.accounts", "Accounts"),
        "adjustments": ("moovio_sdk.adjustments", "Adjustments"),
        "apple_pay": ("moovio_sdk.apple_pay", "ApplePay"),
        "bank_accounts": ("moovio_sdk.bank_accounts", "BankAccounts"),
        "branding": ("moovio_sdk.branding", "Branding"),
        "capabilities": ("moovio_sdk.capabilities", "Capabilities"),
        "cards": ("moovio_sdk.cards", "Cards"),
        "disputes": ("moovio_sdk.disputes", "Disputes"),
        "fee_plans": ("moovio_sdk.fee_plans", "FeePlans"),
        "files": ("moovio_sdk.files", "Files"),
        "images": ("moovio_sdk.images", "Images"),
        "invoices": ("moovio_sdk.invoices", "Invoices"),
        "payment_links": ("moovio_sdk.payment_links", "PaymentLinks"),
        "payment_methods": ("moovio_sdk.payment_methods", "PaymentMethods"),
        "products": ("moovio_sdk.products", "Products"),
        "representatives": ("moovio_sdk.representatives", "Representatives"),
        "scheduling": ("moovio_sdk.scheduling", "Scheduling"),
        "statements": ("moovio_sdk.statements", "Statements"),
        "sweeps": ("moovio_sdk.sweeps", "Sweeps"),
        "account_terminal_applications": (
            "moovio_sdk.account_terminal_applications",
            "AccountTerminalApplications",
        ),
        "support": ("moovio_sdk.support", "Support"),
        "transfers": ("moovio_sdk.transfers", "Transfers"),
        "underwriting": ("moovio_sdk.underwriting", "Underwriting"),
        "wallets": ("moovio_sdk.wallets", "Wallets"),
        "wallet_transactions": ("moovio_sdk.wallet_transactions", "WalletTransactions"),
        "avatars": ("moovio_sdk.avatars", "Avatars"),
        "end_to_end_encryption": (
            "moovio_sdk.end_to_end_encryption",
            "EndToEndEncryption",
        ),
        "enriched_address": ("moovio_sdk.enriched_address", "EnrichedAddress"),
        "enriched_profile": ("moovio_sdk.enriched_profile", "EnrichedProfile"),
        "webhooks": ("moovio_sdk.webhooks", "Webhooks"),
        "industries": ("moovio_sdk.industries", "Industries"),
        "institutions": ("moovio_sdk.institutions", "Institutions"),
        "issuing_transactions": (
            "moovio_sdk.issuing_transactions",
            "IssuingTransactions",
        ),
        "card_issuing": ("moovio_sdk.card_issuing", "CardIssuing"),
        "authentication": ("moovio_sdk.authentication", "Authentication"),
        "onboarding": ("moovio_sdk.onboarding", "Onboarding"),
        "ping": ("moovio_sdk.ping", "Ping"),
        "receipts": ("moovio_sdk.receipts", "Receipts"),
        "terminal_applications": (
            "moovio_sdk.terminal_applications",
            "TerminalApplications",
        ),
    }

    def __init__(
        self,
        security: Optional[
            Union[components.Security, Callable[[], components.Security]]
        ] = None,
        x_moov_version: Optional[str] = None,
        server_idx: Optional[int] = None,
        url_params: Optional[Dict[str, str]] = None,
        server_url: Optional[str] = None,
        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 security: The security details required for authentication
        :param x_moov_version: Configures the x_moov_version parameter for all supported operations
        :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."

        if server_url is not None:
            if url_params is not None:
                server_url = utils.template_url(server_url, url_params)

        _globals = internal.Globals(
            x_moov_version=utils.get_global_from_env(
                x_moov_version, "MOOV_X_MOOV_VERSION", str
            ),
        )

        BaseSDK.__init__(
            self,
            SDKConfiguration(
                client=client,
                client_supplied=client_supplied,
                async_client=async_client,
                async_client_supplied=async_client_supplied,
                globals=_globals,
                security=security,
                server_url=server_url,
                server_idx=server_idx,
                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
