from dasl_api import (
    CoreV1DataSource,
    CoreV1DataSourceList,
    CommonV1ObjectMeta,
    CoreV1DataSourceSpec,
    CoreV1Schedule,
    CoreV1DataSourceSpecSilver,
    CoreV1DataSourceSpecGold,
    CoreV1DataSourceAutoloaderSpec,
    CoreV1DataSourceSpecBronze,
    CoreV1DataSourceSpecCustom,
)

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

from dasl_client.errors.errors import NotFoundError, handle_errors


class DatasourceMixin(BaseMixin):
    @handle_errors
    def get_datasource(self, name: str) -> CoreV1DataSource:
        """
        Get a previously created datasource by name.

        :param name: The name of the datasource to fetch
        :return: a CoreV1DataSource object containing the spec and status of the datasource.
        :raises: NotFoundError if the datasource does not exist
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()
        return openapi_client.CoreV1Api(auth).core_v1_get_data_source(
            workspace, name
        )

    @handle_errors
    def delete_datasource(self, name: str) -> None:
        """
        Delete a datasource, request all deployed resource be removed as well. Note,
        this call is an instruction to ASL to delete the datasource, it does not
        block until the datasource has been deleted.

        :param name: The name of the datasource to delete
        :raises: NotFoundError if the datasource does not exist
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()
        openapi_client.CoreV1Api(auth).core_v1_delete_data_source(
            workspace, name
        )

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

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

    @handle_errors
    def create_datasource(
        self,
        name: str,
        source: str,
        source_type: str,
        use_preset: str,
        schedule: CoreV1Schedule,
        custom_notebook_path: Optional[str] = None,
        bronze: Optional[CoreV1DataSourceSpecBronze] = None,
        silver: Optional[CoreV1DataSourceSpecSilver] = None,
        gold: Optional[CoreV1DataSourceSpecGold] = None,
        autoloader_override: Optional[CoreV1DataSourceAutoloaderSpec] = None,
    ) -> CoreV1DataSource:
        """
        Create a datasource with the information provided in this request.
        Note, this request is an instruction and will return before the new
        datasource has been created. It can take time for the changes to
        propagate and the relevant resources to be deployed.

        :param name: Name of the datasource to create.
        :param source: Name of originator of the data we will import (GCP, AWS, Okta, etc).
        :param source_type: The type of data we are importing from the source (e.g. S3, LB, etc).
        :param use_preset: The name of the preset to use for this data source.
        :param input: Describes what and how to import data into bronze tables.
        :param schedule: The schedule to apply to the datasource.
        :param custom_notebook_path: An optional path to the notebook containing custom
                                     functions for the datasource.
        :param bronze: The bronze data source spec.
        :param silver: The silver data source spec.
        :param gold: The  gold data source spec.
        :param autoloader_override: An optional autoloader override for the datasource.
        :return: The datasource as recorded by the server.
        :raises ConflictError: if the datasource already exists.
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()

        spec = CoreV1DataSourceSpec(
            source=source,
            use_preset=use_preset,
            source_type=source_type,
            autoloader=autoloader_override,
            schedule=schedule,
            custom=CoreV1DataSourceSpecCustom(notebook=custom_notebook_path),
            bronze=bronze,
            silver=silver,
            gold=gold,
        )
        meta = CommonV1ObjectMeta(name=name, workspace=workspace)
        request = CoreV1DataSource(metadata=meta, spec=spec)
        return openapi_client.CoreV1Api(auth).core_v1_create_data_source(
            workspace, request
        )

    @handle_errors
    def replace_datasource(
        self,
        name: str,
        source: str,
        source_type: str,
        use_preset: str,
        schedule: CoreV1Schedule,
        custom_notebook_path: Optional[str] = None,
        bronze: Optional[CoreV1DataSourceSpecBronze] = None,
        silver: Optional[CoreV1DataSourceSpecSilver] = None,
        gold: Optional[CoreV1DataSourceSpecGold] = None,
        autoloader_override: Optional[CoreV1DataSourceAutoloaderSpec] = None,
    ) -> CoreV1DataSource:
        """
        Replace an existing datasource with the information provided in this request.
        Note, this request is an instruction and will return before the new
        datasource has been created. It can take time for the changes to
        propagate and the relevant resources to be deployed.

        :param name: Name of the datasource to create.
        :param source: Name of originator of the data we will import (GCP, AWS, Okta, etc).
        :param source_type: The type of data we are importing from the source (e.g. S3, LB, etc).
        :param use_preset: The name of the preset to use for this data source.
        :param schedule: The schedule to apply to the datasource.
        :param custom_notebook_path: An optional path to the notebook containing custom
                                     functions for the datasource.
        :param bronze: The bronze data source spec.
        :param silver: The silver data source spec.
        :param gold: The  gold data source spec.
        :param autoloader_override: An optional autoloader override for the datasource.
        :return: The datasource as recorded by the server.
        :raises NotFoundError: if no datasource with the provided name exists to replace.
        """
        auth = self.auth.client()
        workspace = self.auth.workspace()

        spec = CoreV1DataSourceSpec(
            source=source,
            use_preset=use_preset,
            source_type=source_type,
            autoloader=autoloader_override,
            schedule=schedule,
            custom=CoreV1DataSourceSpecCustom(notebook=custom_notebook_path),
            bronze=bronze,
            silver=silver,
            gold=gold,
        )
        meta = CommonV1ObjectMeta(name=name, workspace=workspace)
        request = CoreV1DataSource(metadata=meta, spec=spec)

        return openapi_client.CoreV1Api(auth).core_v1_replace_data_source(
            workspace, name, request
        )
