from dasl_api import (
    CommonV1ObjectMeta,
    CoreV1Transform,
    CoreV1TransformList,
    CoreV1TransformSpec,
    CoreV1TransformSpecStream,
)

from dasl_client.core.base import BaseMixin
from typing import Optional
import dasl_api as openapi_client

from dasl_client.errors.errors import handle_errors


class TransformMixin(BaseMixin):
    @handle_errors
    def get_transform(self, name: str) -> CoreV1Transform:
        """
        Fetch the transform associated with the supplied name.

        :param name: The name of the transform to fetch
        :return: The transform object
        :raises TransformNotFound: if the transform was not found
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()
        return openapi_client.CoreV1Api(auth).core_v1_get_transform(
            workspace, name
        )

    @handle_errors
    def delete_transform(self, name: str) -> None:
        """
        Delete the transform associated with the supplied name.

        :param name: Name of the transform to delete
        :return:
        :raises TransformNotFound: if the transform was not found
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()
        openapi_client.CoreV1Api(auth).core_v1_delete_transform(
            workspace, name
        )

    @handle_errors
    def list_transforms(
        self, cursor: Optional[str] = None, limit: Optional[int] = None
    ) -> CoreV1TransformList:
        """
        List all transforms in the current client.

        :param cursor: An optional identifier generated by the server. This is
                       used to fetch transforms following on from prior list
                       request which returned a cursor.
        :param limit:  An optional limit on the number of transforms to return.
        :return: A CoreV1RuleList containing the transforms returned.
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()
        return openapi_client.CoreV1Api(auth).core_v1_list_transforms(
            workspace=workspace, cursor=cursor, limit=limit
        )

    @handle_errors
    def create_transform(
        self,
        name: str,
        schedule: Optional[str] = None,
        output_table: Optional[str] = None,
        stream: Optional[CoreV1TransformSpecStream] = None,
    ) -> CoreV1Transform:
        """
        Create a new transform with the supplied name. Note, this request is an
        instruction and will return before the new rule has been created. It
        can take time for the changes to propagate and the relevant resources
        to be deployed.

        :param name: name of the transform
        :param schedule: The schedule associated with the transform
        :param output_table: The name of the destination table
        :param stream: The data source to apply the transform to
        :return: The transform object as recorded by the server.
        :raises ConflictError: if a transform with the same name already exists.
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()

        spec = CoreV1TransformSpec(
            schedule=schedule,
            output_table=output_table,
            stream=stream,
        )
        meta = CommonV1ObjectMeta(name=name, workspace=workspace)
        request = CoreV1Transform(metadata=meta, spec=spec)
        return openapi_client.CoreV1Api(auth).core_v1_create_transform(
            workspace, request
        )

    @handle_errors
    def replace_transform(
        self,
        name: str,
        schedule: Optional[str] = None,
        output_table: Optional[str] = None,
        stream: Optional[CoreV1TransformSpecStream] = None,
    ) -> CoreV1Transform:
        """
        Replace a transform associated with the supplied name. Note, this
        request is an instruction and will return before the new rule has been
        created. It can take time for the changes to propagate and the relevant
        resources to be deployed.

        :param name: name of the transform
        :param schedule: The schedule associated with the transform
        :param output_table: The name of the destination table
        :param stream: The data source to apply the transform to
        :return: The transform object as recorded by the server.
        :raises NotFoundError: If no transform with the provided name exists to
                               replace.
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()

        spec = CoreV1TransformSpec(
            schedule=schedule,
            output_table=output_table,
            stream=stream,
        )
        meta = CommonV1ObjectMeta(name=name, workspace=workspace)
        request = CoreV1Transform(metadata=meta, spec=spec)
        return openapi_client.CoreV1Api(auth).core_v1_replace_transform(
            workspace, name, request
        )
