import json

import lara_django_base_grpc.v1.lara_django_base_pb2 as lara_django_base_pb2
import lara_django_base_grpc.v1.lara_django_base_pb2_grpc as lara_django_base_pb2_grpc

import lara_django_samples_grpc.v1.lara_django_samples_pb2 as lara_django_samp_pb2
import lara_django_samples_grpc.v1.lara_django_samples_pb2_grpc as lara_django_samp_pb2_grpc


class LARAsamplesInterface:
    """High level interface to the LARA samples API."""

    def __init__(self, channel, default_namespace=None) -> None:
        if default_namespace is not None:
            self.default_namespace = default_namespace
        self.namespaceURN_client = (
            lara_django_base_pb2_grpc.NamespaceByURIControllerStub(channel)
        )

        self.sample_class_client = (
            lara_django_samp_pb2_grpc.SampleClassByIRIControllerStub(channel)
        )
        self.sample_client = lara_django_samp_pb2_grpc.SampleControllerStub(channel)
        self.sample_full_client = lara_django_samp_pb2_grpc.SampleFullControllerStub(
            channel
        )

    def create(
        self,
        namespace_URI: str = None,
        sample_class_iri: str = None,
        sample: dict = None,
    ):
        if namespace_URI is None and self.default_namespace is not None:
            namespace_URI = self.default_namespace
        if namespace_URI is None:
            raise ValueError("No namespace is given.")
        namespace_id = self.namespaceURN_client.Retrieve(
            lara_django_base_pb2.NamespaceRetrieveRequest(uri=namespace_URI)
        ).namespace_id
        if sample_class_iri is None:
            raise ValueError("No sample class IRI is given.")
        sampleclass_id = self.sample_class_client.Retrieve(
            lara_django_samp_pb2.SampleClassRetrieveRequest(IRI=sample_class_iri)
        ).sample_class_id
        sample["namespace"] = namespace_id
        sample["sample_class"] = sample_class_id
        return self.sample_client.Create(lara_django_samp_pb2.SampleRequest(**sample))

    def retrieve(
        self,
        sample_id: str = None,
        sample_name: str = None,
        sample_name_full: str = None,
        barcode: str = None,
    ):
        if sample_id is not None:
            return self.sample_client.Retrieve(
                lara_django_samp_pb2.SampleRetrieveRequest(sample_id=sample_id)
            )
        elif sample_name is not None:
            filter_dict = {"name": sample_name}
            metadata = (("filters", (json.dumps(filter_dict))),)
            return self.sample_client.List(
                lara_django_samp_pb2.SampleListRequest(), metadata=metadata
            )
        elif sample_name_full is not None:
            filter_dict = {"name_full": sample_name_full}
            metadata = (("filters", (json.dumps(filter_dict))),)
            return self.sample_client.List(
                lara_django_samp_pb2.SampleListRequest(), metadata=metadata
            )
        elif barcode is not None:
            filter_dict = {"barcode": barcode}
            metadata = (("filters", (json.dumps(filter_dict))),)
            return self.sample_client.List(
                lara_django_samp_pb2.SampleListRequest(), metadata=metadata
            )

    def list(self, filter_dict: dict = None):
        if filter_dict is None:
            return self.sample_client.List(lara_django_samp_pb2.SampleListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return self.sample_client.List(
                lara_django_samp_pb2.SampleListRequest(), metadata=metadata
            )

    def list_full(self, filter_dict: dict = {}):
        if filter_dict is None:
            return self.sample_full_client.List(
                lara_django_samp_pb2.SampleFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return self.sample_full_client.List(
                lara_django_samp_pb2.SampleFullListRequest(), metadata=metadata
            )

    def update(self, sample_id: str = None, sample: dict = None):
        return self.sample_client.Update(
            lara_django_samp_pb2.SampleRequest(sample_id=sample_id, **sample)
        )

    def delete(self, sample_id: str = None):
        return self.sample_client.Delete(
            lara_django_base_pb2.SampleRequest(sample_id=sample_id)
        )
