"""
Snowflake External Volume API.

The Snowflake External Volume API is a REST API that you can use to access, update, and perform certain actions on External Volume resource in a Snowflake database.  # 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.
"""

from typing import TYPE_CHECKING, Iterator, Optional, TypeVar, Union

from snowflake.core._common import AccountObjectCollectionParent, CreateMode, 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.external_volume._generated.models.external_volume import ExternalVolume

from .external_volume_api import ExternalVolumeApi


if TYPE_CHECKING:
    from snowflake.core import Root


T = TypeVar("T")


class ExternalVolumeCollectionBase(AccountObjectCollectionParent["ExternalVolumeResource"]):
    _identifier_requires_args: bool = False

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

    @api_telemetry
    def create(
        self, external_volume: ExternalVolume, mode: Optional[Union[CreateMode, str]] = None
    ) -> "ExternalVolumeResource":  # noqa: F821
        """Create an external volume.

        Parameters
        __________
        external_volume: ExternalVolume
             (required)
        mode: Union[CreateMode, str]
             Parameter allowing support for different modes of resource creation. Possible values include: - `errorIfExists`: Throws an error if you try to create a resource that already exists. - `orReplace`: Automatically replaces the existing resource with the current one. - `ifNotExists`: Creates a new resource when an alter is requested for a non-existent resource.
        """
        if isinstance(mode, str):
            mode = CreateMode[mode].value

        self._api.create_external_volume(
            external_volume=external_volume,
            create_mode=mode,
            async_req=False,
        )
        if self._identifier_requires_args:
            return self._ref_class(get_function_name_with_args(external_volume), self)
        return self._ref_class(external_volume.name, self)

    @api_telemetry
    def create_async(
        self, external_volume: ExternalVolume, mode: Optional[Union[CreateMode, str]] = None
    ) -> PollingOperation["ExternalVolumeResource"]:  # noqa: F821
        """An asynchronous version of :func:`create`.

        Refer to :class:`~snowflake.core.PollingOperation` for more information on asynchronous execution and
        the return type.
        """
        if isinstance(mode, str):
            mode = CreateMode[mode].value

        future = self._api.create_external_volume(
            external_volume=external_volume,
            create_mode=mode,
            async_req=True,
        )
        if self._identifier_requires_args:
            return PollingOperation(
                future, lambda _: self._ref_class(get_function_name_with_args(external_volume), self)
            )
        return PollingOperation(
            future,
            lambda _: self._ref_class(
                external_volume if isinstance(external_volume, str) else external_volume.name, self
            ),
        )

    @api_telemetry
    def iter(self, *, like: Optional[str] = None) -> Iterator[ExternalVolume]:
        """List external volumes.

        Parameters
        __________
        like: str
             Parameter to filter the command output by resource name. Uses case-insensitive pattern matching, with support for SQL wildcard characters.
        """
        resources = self._api.list_external_volumes(
            like=like,
            async_req=False,
        )
        return iter(resources)

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

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

        return PollingOperations.iterator(future)


class ExternalVolumeResourceBase(ObjectReferenceMixin["ExternalVolumeCollection"]):
    _collection_class: ExternalVolumeCollectionBase
    _identifier_requires_args: bool = False
    _plural_name: str

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

    @api_telemetry
    def fetch(
        self,
    ) -> ExternalVolume:
        """Fetch an external volume.

        Parameters
        __________
        """
        result = self.collection._api.fetch_external_volume(
            self._identifier,
            async_req=False,
        )
        return result

    @api_telemetry
    def fetch_async(
        self,
    ) -> PollingOperation[ExternalVolume]:
        """An asynchronous version of :func:`fetch`.

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

        return PollingOperations.identity(future)

    @api_telemetry
    def undrop(
        self,
    ) -> None:
        """Undrop an external volume.

        Parameters
        __________
        """
        self.collection._api.undrop_external_volume(
            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_external_volume(
            self._identifier,
            async_req=True,
        )
        return PollingOperations.empty(future)

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

        Parameters
        __________
        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_external_volume(
            self._identifier,
            if_exists=if_exists,
            async_req=False,
        )

    @api_telemetry
    def drop_async(
        self,
        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_external_volume(
            self._identifier,
            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)
