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

if TYPE_CHECKING:
    from squadcast.additionalresponders import AdditionalResponders
    from squadcast.analytics import Analytics
    from squadcast.auditlogs import AuditLogs
    from squadcast.communicationcards import CommunicationCards
    from squadcast.componentgroups import ComponentGroups
    from squadcast.components import Components
    from squadcast.dedupkeys import DedupKeys
    from squadcast.escalationpolicies_sdk import EscalationPoliciesSDK
    from squadcast.exports import Exports
    from squadcast.exportschedule import ExportSchedule
    from squadcast.extensions import Extensions
    from squadcast.globaleventrules import GlobalEventRules
    from squadcast.globaloncallreminderrules_sdk import GlobalOncallReminderRulesSDK
    from squadcast.incidents import Incidents
    from squadcast.issues import Issues
    from squadcast.maintenances import Maintenances
    from squadcast.overlays import Overlays
    from squadcast.overrides import Overrides
    from squadcast.postmortems_sdk import PostmortemsSDK
    from squadcast.rotations import Rotations
    from squadcast.rules import Rules
    from squadcast.rulesets import Rulesets
    from squadcast.runbooks_sdk import RunbooksSDK
    from squadcast.schedules_sdk import SchedulesSDK
    from squadcast.services_sdk import ServicesSDK
    from squadcast.slos_sdk import SlosSDK
    from squadcast.snoozenotifications import SnoozeNotifications
    from squadcast.squads_sdk import SquadsSDK
    from squadcast.squadsv4 import SquadsV4
    from squadcast.statuspages_sdk_1 import StatusPagesSDK1
    from squadcast.statuspages_sdk_2 import StatuspagesSDK2
    from squadcast.subscribers import Subscribers
    from squadcast.teams import Teams
    from squadcast.users import Users
    from squadcast.webforms_sdk import WebformsSDK
    from squadcast.webhooks import Webhooks
    from squadcast.workflows_sdk import WorkflowsSDK


class SquadcastSDK(BaseSDK):
    r"""Squadcast: ## Overview
    The Squadcast API provides developers the capability to extend and utilize Squadcast in conjunction with other services. Our API has resource-oriented URLs, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

    > **Note:** Customers using the V2 version of the Squadcast API would need to migrate to Squadcast API V3, as the former would be deprecated shortly.

    ### Service Regions

    Squadcast allows customers to choose the geographic region of the Squadcast data centers that host their account. When signing up, you can choose the service region. Currently, the available options are the United States (US) and Europe (EU).

    | Service Region | API Endpoints |
    |---|---|
    | US | Authentication: https://auth.squadcast.com · Other APIs: https://api.squadcast.com |
    | EU | Authentication: https://auth.eu.squadcast.com · Other APIs: https://api.eu.squadcast.com |

    ### Authentication

    In order to access the API programmatically, HTTP bearer authentication needs to be used. HTTP bearer authentication must be constructed using an `access_token`, passed as the `Authorization` header for each request, for example `Authorization: Bearer eyJleHAiOjE2MzU1OTE1OTIsImp0aSI6Im`.

    Steps to procure the `access_token`:

    1. Generate a `refresh_token` (API Token) from the Squadcast web app. More details on how to get the `refresh_token` can be found in the Squadcast support documentation.
    2. Call the authentication API with the `refresh_token` to obtain an `access_token`.
    3. Use the `access_token` as a Bearer token in the `Authorization` header for all subsequent API requests.

    #### Example — Generating an Access Token

    ```bash
    curl --location --request GET 'https://auth.squadcast.com/oauth/access-token' \ 
    --header 'X-Refresh-Token: 0d2a1a9a454dxxxxxxxxxxxx'
    ```

    The API response will look similar to:

    ```json
    {
    \"data\": {
    \"access_token\": \"eyJhbGciOiJIUxxxxx.xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxx\",
    \"expires_at\": 1587412870,
    \"issued_at\": 1587240070,
    \"refresh_token\": \"0d2a1a9a454dxxxxxxxxxxxx\",
    \"type\": \"bearer\" 
    }
    }
    ```

    ### Access Control

    There are three different types of user roles in Squadcast: `account_owner`, `stakeholder`, and `user`. Refresh tokens upon creation are mapped with one of the mentioned user roles, and access to different resources is dependent on the permissions granted to these roles. For more information, please refer to the Squadcast support documentation.

    ### Authorization

    The access token authorizes users the ability to access different APIs, based on the user roles described above. Pass the access token as a Bearer token in the `Authorization` header of every request.
    """

    analytics: "Analytics"
    audit_logs: "AuditLogs"
    escalation_policies: "EscalationPoliciesSDK"
    exports: "Exports"
    extensions: "Extensions"
    webhooks: "Webhooks"
    incidents: "Incidents"
    global_event_rules: "GlobalEventRules"
    rulesets: "Rulesets"
    rules: "Rules"
    global_oncall_reminder_rules: "GlobalOncallReminderRulesSDK"
    postmortems: "PostmortemsSDK"
    communication_cards: "CommunicationCards"
    runbooks: "RunbooksSDK"
    additional_responders: "AdditionalResponders"
    snooze_notifications: "SnoozeNotifications"
    users: "Users"
    services: "ServicesSDK"
    dedup_keys: "DedupKeys"
    overlays: "Overlays"
    slos: "SlosSDK"
    teams: "Teams"
    webforms: "WebformsSDK"
    workflows: "WorkflowsSDK"
    schedules: "SchedulesSDK"
    export_schedule: "ExportSchedule"
    overrides: "Overrides"
    rotations: "Rotations"
    squads: "SquadsSDK"
    squads_v4: "SquadsV4"
    status_pages: "StatusPagesSDK1"
    components: "Components"
    component_groups: "ComponentGroups"
    issues: "Issues"
    maintenances: "Maintenances"
    statuspages: "StatuspagesSDK2"
    subscribers: "Subscribers"
    _sub_sdk_map = {
        "analytics": ("squadcast.analytics", "Analytics"),
        "audit_logs": ("squadcast.auditlogs", "AuditLogs"),
        "escalation_policies": (
            "squadcast.escalationpolicies_sdk",
            "EscalationPoliciesSDK",
        ),
        "exports": ("squadcast.exports", "Exports"),
        "extensions": ("squadcast.extensions", "Extensions"),
        "webhooks": ("squadcast.webhooks", "Webhooks"),
        "incidents": ("squadcast.incidents", "Incidents"),
        "global_event_rules": ("squadcast.globaleventrules", "GlobalEventRules"),
        "rulesets": ("squadcast.rulesets", "Rulesets"),
        "rules": ("squadcast.rules", "Rules"),
        "global_oncall_reminder_rules": (
            "squadcast.globaloncallreminderrules_sdk",
            "GlobalOncallReminderRulesSDK",
        ),
        "postmortems": ("squadcast.postmortems_sdk", "PostmortemsSDK"),
        "communication_cards": ("squadcast.communicationcards", "CommunicationCards"),
        "runbooks": ("squadcast.runbooks_sdk", "RunbooksSDK"),
        "additional_responders": (
            "squadcast.additionalresponders",
            "AdditionalResponders",
        ),
        "snooze_notifications": (
            "squadcast.snoozenotifications",
            "SnoozeNotifications",
        ),
        "users": ("squadcast.users", "Users"),
        "services": ("squadcast.services_sdk", "ServicesSDK"),
        "dedup_keys": ("squadcast.dedupkeys", "DedupKeys"),
        "overlays": ("squadcast.overlays", "Overlays"),
        "slos": ("squadcast.slos_sdk", "SlosSDK"),
        "teams": ("squadcast.teams", "Teams"),
        "webforms": ("squadcast.webforms_sdk", "WebformsSDK"),
        "workflows": ("squadcast.workflows_sdk", "WorkflowsSDK"),
        "schedules": ("squadcast.schedules_sdk", "SchedulesSDK"),
        "export_schedule": ("squadcast.exportschedule", "ExportSchedule"),
        "overrides": ("squadcast.overrides", "Overrides"),
        "rotations": ("squadcast.rotations", "Rotations"),
        "squads": ("squadcast.squads_sdk", "SquadsSDK"),
        "squads_v4": ("squadcast.squadsv4", "SquadsV4"),
        "status_pages": ("squadcast.statuspages_sdk_1", "StatusPagesSDK1"),
        "components": ("squadcast.components", "Components"),
        "component_groups": ("squadcast.componentgroups", "ComponentGroups"),
        "issues": ("squadcast.issues", "Issues"),
        "maintenances": ("squadcast.maintenances", "Maintenances"),
        "statuspages": ("squadcast.statuspages_sdk_2", "StatuspagesSDK2"),
        "subscribers": ("squadcast.subscribers", "Subscribers"),
    }

    def __init__(
        self,
        refresh_token_auth: Union[str, Callable[[], str]],
        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 refresh_token_auth: The refresh_token_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(refresh_token_auth):
            # pylint: disable=unnecessary-lambda-assignment
            security = lambda: models.Security(refresh_token_auth=refresh_token_auth())
        else:
            security = models.Security(refresh_token_auth=refresh_token_auth)

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

        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,
                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
