"""
Snowflake Account API.

The Snowflake Account API is a REST API that you can use to access, update, and perform certain actions on Account resource in Snowflake.  # noqa: E501

The version of the OpenAPI document: 0.0.1
Contact: support@snowflake.com
Generated by: https://openapi-generator.tech

Do not edit this file manually.
"""

import warnings

from typing import TYPE_CHECKING, Iterator, Optional, TypeVar

from snowflake.core._common import AccountObjectCollectionParent, ObjectReferenceMixin
from snowflake.core._generated.api_client import StoredProcApiClient
from snowflake.core._internal.telemetry import api_telemetry
from snowflake.core._operation import PollingOperation, PollingOperations
from snowflake.core._utils import get_function_name_with_args, replace_function_name_in_name_with_args
from snowflake.core.account._generated.models.account import Account

from .account_api import AccountApi


if TYPE_CHECKING:
    from snowflake.core import Root


T = TypeVar("T")


class AccountCollectionBase(AccountObjectCollectionParent["AccountResource"]):
    _identifier_requires_args: bool = False

    def __init__(self, root: "Root", resource_class: type[T]) -> None:
        super().__init__(root, resource_class)
        self._api = AccountApi(
            root=self.root, resource_class=self._ref_class, sproc_client=StoredProcApiClient(root=self.root)
        )

    @api_telemetry
    def create(self, account: Account) -> "AccountResource":  # noqa: F821
        """Create an account.

        Parameters
        __________
        account: Account
             (required)
        """
        self._api.create_account(
            account=account,
            async_req=False,
        )
        if self._identifier_requires_args:
            return self._ref_class(get_function_name_with_args(account), self)
        return self._ref_class(account.name, self)

    @api_telemetry
    def create_async(self, account: Account) -> PollingOperation["AccountResource"]:  # noqa: F821
        """An asynchronous version of :func:`create`.

        Refer to :class:`~snowflake.core.PollingOperation` for more information on asynchronous execution and
        the return type.
        """
        future = self._api.create_account(
            account=account,
            async_req=True,
        )
        if self._identifier_requires_args:
            return PollingOperation(future, lambda _: self._ref_class(get_function_name_with_args(account), self))
        return PollingOperation(
            future, lambda _: self._ref_class(account if isinstance(account, str) else account.name, self)
        )

    @api_telemetry
    def iter(
        self,
        *,
        like: Optional[str] = None,
        limit: Optional[int] = None,
        history: Optional[bool] = None,
        show_limit: Optional[int] = None,
    ) -> Iterator[Account]:
        """List accounts.

        Parameters
        __________
        like: str
             Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters.
        limit: int
             Parameter to limit the maximum number of rows returned by a command.
        history: bool
             Optionally includes dropped accounts that have not yet been purged.
        """
        if show_limit is not None:
            if limit is not None:
                raise ValueError("Cannot specify both 'limit' and 'show_limit'. Use only one of them.")
            warnings.warn(DeprecationWarning("'show_limit' is deprecated, use 'limit' instead."))  # noqa: B028
            limit = show_limit

        resources = self._api.list_accounts(
            like=like,
            show_limit=limit,
            history=history,
            async_req=False,
        )
        return iter(resources)

    @api_telemetry
    def iter_async(
        self,
        *,
        like: Optional[str] = None,
        limit: Optional[int] = None,
        history: Optional[bool] = None,
        show_limit: Optional[int] = None,
    ) -> PollingOperation[Iterator[Account]]:
        """An asynchronous version of :func:`iter`.

        Refer to :class:`~snowflake.core.PollingOperation` for more information on asynchronous execution and
        the return type.
        """
        if show_limit is not None:
            if limit is not None:
                raise ValueError("Cannot specify both 'limit' and 'show_limit'. Use only one of them.")
            warnings.warn(DeprecationWarning("'show_limit' is deprecated, use 'limit' instead."))  # noqa: B028
            limit = show_limit

        future = self._api.list_accounts(
            like=like,
            show_limit=limit,
            history=history,
            async_req=True,
        )

        return PollingOperations.iterator(future)


class AccountResourceBase(ObjectReferenceMixin["AccountCollection"]):
    _collection_class: AccountCollectionBase
    _identifier_requires_args: bool = False
    _plural_name: str

    def __init__(self, name: str, collection_class: AccountCollectionBase) -> None:
        self.collection = collection_class
        if self._identifier_requires_args:
            self.name_with_args = name
        else:
            self.name = name

    @api_telemetry
    def undrop(
        self,
    ) -> None:
        """Restore an account.

        Parameters
        __________
        """
        self.collection._api.undrop_account(
            self._identifier,
            async_req=False,
        )

    @api_telemetry
    def undrop_async(
        self,
    ) -> PollingOperation[None]:
        """An asynchronous version of :func:`undrop`.

        Refer to :class:`~snowflake.core.PollingOperation` for more information on asynchronous execution and
        the return type.
        """
        future = self.collection._api.undrop_account(
            self._identifier,
            async_req=True,
        )
        return PollingOperations.empty(future)

    @api_telemetry
    def drop(
        self,
        grace_period_in_days: int,
        if_exists: Optional[bool] = None,
    ) -> None:
        """Delete an account.

        Parameters
        __________
        grace_period_in_days: int
             Specifies the number of days during which the account can be restored (“undropped”). The minimum is 3 days and the maximum is 90 days. (required)
        if_exists: bool
             Parameter that specifies how to handle the request for a resource that does not exist: - `true`: The endpoint does not throw an error if the resource does not exist. It returns a 200 success response, but does not take any action on the resource. - `false`: The endpoint throws an error if the resource doesn't exist.
        """
        self.collection._api.delete_account(
            self._identifier,
            grace_period_in_days=grace_period_in_days,
            if_exists=if_exists,
            async_req=False,
        )

    @api_telemetry
    def drop_async(
        self,
        grace_period_in_days: int,
        if_exists: Optional[bool] = None,
    ) -> PollingOperation[None]:
        """An asynchronous version of :func:`drop`.

        Refer to :class:`~snowflake.core.PollingOperation` for more information on asynchronous execution and
        the return type.
        """
        future = self.collection._api.delete_account(
            self._identifier,
            grace_period_in_days=grace_period_in_days,
            if_exists=if_exists,
            async_req=True,
        )
        return PollingOperations.empty(future)

    @property
    def _identifier(self) -> str:
        """Get the identifier for this resource."""
        if self._identifier_requires_args:
            return self.name_with_args
        return self.name

    def _set_new_name(self, target_name: str) -> None:
        """Set a new name for the resource."""
        if self._identifier_requires_args:
            old_name = self.name_with_args
            self.name_with_args = replace_function_name_in_name_with_args(self.name_with_args, target_name)
        else:
            old_name = self.name
            self.name = target_name

        # Update the collection reference to point to the new name
        self.collection.update_reference(old_name=old_name, new_name=self._identifier, resource=self)
