from __future__ import annotations

from collections.abc import AsyncIterator, Sequence
from typing import TYPE_CHECKING, overload

from cognite.client._api_client import APIClient
from cognite.client._constants import DEFAULT_LIMIT_READ
from cognite.client.data_classes.simulators.filters import SimulatorIntegrationFilter
from cognite.client.data_classes.simulators.simulators import SimulatorIntegration, SimulatorIntegrationList
from cognite.client.utils._experimental import FeaturePreviewWarning
from cognite.client.utils._identifier import IdentifierSequence
from cognite.client.utils.useful_types import SequenceNotStr

if TYPE_CHECKING:
    from cognite.client import AsyncCogniteClient
    from cognite.client.config import ClientConfig


class SimulatorIntegrationsAPI(APIClient):
    _RESOURCE_PATH = "/simulators/integrations"

    def __init__(self, config: ClientConfig, api_version: str | None, cognite_client: AsyncCogniteClient) -> None:
        super().__init__(config, api_version, cognite_client)
        self._DELETE_LIMIT = 1
        self._warning = FeaturePreviewWarning(
            api_maturity="General Availability", sdk_maturity="alpha", feature_name="Simulators"
        )

    @overload
    def __call__(
        self,
        chunk_size: int,
        simulator_external_ids: str | SequenceNotStr[str] | None = None,
        active: bool | None = None,
        limit: int | None = None,
    ) -> AsyncIterator[SimulatorIntegrationList]: ...

    @overload
    def __call__(
        self,
        chunk_size: None = None,
        simulator_external_ids: str | SequenceNotStr[str] | None = None,
        active: bool | None = None,
        limit: int | None = None,
    ) -> AsyncIterator[SimulatorIntegration]: ...

    async def __call__(
        self,
        chunk_size: int | None = None,
        simulator_external_ids: str | SequenceNotStr[str] | None = None,
        active: bool | None = None,
        limit: int | None = None,
    ) -> AsyncIterator[SimulatorIntegration] | AsyncIterator[SimulatorIntegrationList]:
        """Iterate over simulator integrations

        Fetches simulator integrations as they are iterated over, so you keep a limited number of simulator integrations in memory.

        Args:
            chunk_size (int | None): Number of simulator integrations to return in each chunk. Defaults to yielding one simulator integration a time.
            simulator_external_ids (str | SequenceNotStr[str] | None): Filter on simulator external ids.
            active (bool | None): Filter on active status of the simulator integration.
            limit (int | None): The maximum number of simulator integrations to return, pass None to return all.

        Yields:
            SimulatorIntegration | SimulatorIntegrationList: yields SimulatorIntegration one by one if chunk_size is not specified, else SimulatorIntegrationList objects.
        """  # noqa: DOC404
        integrations_filter = SimulatorIntegrationFilter(simulator_external_ids=simulator_external_ids, active=active)
        async for item in self._list_generator(
            list_cls=SimulatorIntegrationList,
            resource_cls=SimulatorIntegration,
            method="POST",
            filter=integrations_filter.dump(),
            chunk_size=chunk_size,
            limit=limit,
        ):
            yield item

    async def list(
        self,
        limit: int | None = DEFAULT_LIMIT_READ,
        simulator_external_ids: str | SequenceNotStr[str] | None = None,
        active: bool | None = None,
    ) -> SimulatorIntegrationList:
        """`Filter simulator integrations <https://developer.cognite.com/api#tag/Simulator-Integrations/operation/filter_simulator_integrations_simulators_integrations_list_post>`_

        Retrieves a list of simulator integrations that match the given criteria.

        Args:
            limit (int | None): The maximum number of simulator integrations to return, pass None to return all.
            simulator_external_ids (str | SequenceNotStr[str] | None): Filter on simulator external ids.
            active (bool | None): Filter on active status of the simulator integration.

        Returns:
            SimulatorIntegrationList: List of simulator integrations

        Examples:
            List a few simulator integrations:
                >>> from cognite.client import CogniteClient, AsyncCogniteClient
                >>> client = CogniteClient()
                >>> # async_client = AsyncCogniteClient()  # another option
                >>> res = client.simulators.integrations.list(limit=10)

            Iterate over simulator integrations, one-by-one:
                >>> for integration in client.simulators.integrations():
                ...     integration  # do something with the simulator integration

            Filter simulator integrations by simulator external ids and active status:
                >>> res = client.simulators.integrations.list(
                ...     simulator_external_ids=["sim1", "sim2"],
                ...     active=True,
                ... )
        """
        integrations_filter = SimulatorIntegrationFilter(simulator_external_ids=simulator_external_ids, active=active)
        self._warning.warn()
        return await self._list(
            method="POST",
            limit=limit,
            resource_cls=SimulatorIntegration,
            list_cls=SimulatorIntegrationList,
            filter=integrations_filter.dump(),
        )

    async def delete(
        self,
        ids: int | Sequence[int] | None = None,
        external_ids: str | SequenceNotStr[str] | None = None,
    ) -> None:
        """`Delete simulator integrations <https://developer.cognite.com/api#tag/Simulator-Integrations/operation/delete_simulator_integrations_simulators_integrations_delete_post>`_

        Args:
            ids (int | Sequence[int] | None): Id(s) of simulator integrations to delete
            external_ids (str | SequenceNotStr[str] | None): External_id(s) of simulator integrations to delete

        Examples:
            Delete simulator integrations by id or external id:
                >>> from cognite.client import CogniteClient, AsyncCogniteClient
                >>> client = CogniteClient()
                >>> # async_client = AsyncCogniteClient()  # another option
                >>> client.simulators.integrations.delete(ids=[1,2,3], external_ids="foo")
        """
        await self._delete_multiple(
            identifiers=IdentifierSequence.load(ids=ids, external_ids=external_ids),
            wrap_ids=True,
        )
