from collections.abc import AsyncIterator
from typing import Final, Optional, cast

from typing_extensions import Unpack

from ncae_sdk._async.endpoint import AsyncEndpoint
from ncae_sdk._resource import ResourceId
from ncae_sdk._util import map_async
from ncae_sdk.resources._schema import (
    Service,
    ServiceCreate,
    ServiceCreateModel,
    ServiceFilter,
    ServiceFilterModel,
    ServiceUpdate,
    ServiceUpdateModel,
)
from ncae_sdk.types import ServiceConfig


class AsyncServiceEndpoint(AsyncEndpoint):
    BASE_PATH: Final[str] = "automation/v1/service"

    async def list(self, **filters: Unpack[ServiceFilter]) -> AsyncIterator[Service]:
        results = self._list(self.BASE_PATH, ServiceFilterModel, filters)
        return map_async(Service.parse_api, results)

    async def find(self, **filters: Unpack[ServiceFilter]) -> Optional[Service]:
        result = await self._get_by_filters(self.BASE_PATH, ServiceFilterModel, filters)
        return Service.parse_api(result) if result else None

    async def get(self, rid: ResourceId) -> Optional[Service]:
        result = await self._get_by_id(self.BASE_PATH, rid)
        return Service.parse_api(result) if result else None

    async def create(self, **payload: Unpack[ServiceCreate]) -> Service:
        result = await self._create(self.BASE_PATH, ServiceCreateModel, payload)
        return Service.parse_api(result)

    async def update(self, rid: ResourceId, /, **payload: Unpack[ServiceUpdate]) -> Service:
        result = await self._update(self.BASE_PATH, rid, ServiceUpdateModel, payload)
        return Service.parse_api(result)

    async def delete(self, rid: ResourceId) -> bool:
        return await self._delete(self.BASE_PATH, rid)

    async def export_config(self, rid: ResourceId) -> ServiceConfig:
        """
        Exports the specified NCAE service configuration with all its phases as a portable JSON object.
        This exported configuration can be used for backup purposes or to import the service into another NCAE instance.
        """
        response = await self._session.get(f"{self.BASE_PATH}/{rid}/export")
        return cast(ServiceConfig, response.json())

    async def import_config(self, data: ServiceConfig) -> Service:
        """
        Imports a service configuration into NCAE from a JSON object that was previously exported using export_config.
        The provided configuration should include all necessary details for the service and its phases.
        If a service with the same name already exists, it will be updated; otherwise, a new service is created.
        """

        result = await self._session.post(f"{self.BASE_PATH}/import", json=data)
        service = await self.get(result.json()["id"])
        assert service is not None, "Service should exist after import"
        return service
