"""_____________________________________________________________________

:PROJECT: LARAsuite

*lara_django_projects high_level_interface *

:details: lara_django_projects high_level_interface.
         - generated with 'lara-django-dev generate_high_level_interface lara_django_projects
:authors: mark doerr <mark.doerr@uni-greifswald.de>

.. note:: -
.. todo:: - 
________________________________________________________________________
"""

import json
import asyncio
import logging
import grpc
from typing import Union

from google.protobuf.json_format import MessageToDict

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_projects_grpc.v1.lara_django_projects_pb2 as lara_django_projects_pb2
import lara_django_projects_grpc.v1.lara_django_projects_pb2_grpc as lara_django_projects_pb2_grpc

import  lara_django_base_grpc.lara_django_base_data_model as base_dm
import  lara_django_base_grpc.lara_django_base_interface as base_if
from  lara_django_base_grpc.abstract_interface import LARAInterface, export_file, import_file, id_cache, update_image

import  lara_django_projects_grpc.lara_django_projects_data_model as projects_dm 



#_________________  Project  ______________________


class ProjectInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.project_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectclassByIRIControllerStub(channel)
        # )
        
        self.project_client = lara_django_projects_pb2_grpc.ProjectControllerStub(channel)

        # self.project_full_client = lara_django_projects_pb2_grpc.ProjectFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  projects:  list[projects_dm.Project] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.Project]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # projectclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if project_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.project_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectclassRetrieveRequest(iri=project_class_iri)
        #     )
        #     projectclass_id = res.projectclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving projectclass_id: {e}")
        # for project in projects:
        #     project.namespace = self.namespace_id
        #     project.project_class = projectclass_id

        try:
            create_coroutines = ( self.project_client.Create(lara_django_projects_pb2.ProjectRequest(**project.model_dump())) for project in projects )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.project_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating project: {e}")

    @export_file
    async def retrieve(
        self, 
        project_id: str = None,
        project_name: str = None,
        #project_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.Project]:
        filter_list = []
        results_list = []
        if  project_id is not None:
            try:
                res =  await self.project_client.Retrieve(
                    lara_django_projects_pb2.ProjectRetrieveRequest(project_id=project_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving project_id: {e}")

        if project_name is not None:
            filter_list.append({"name": project_name})
        # if project_name_full is not None:
        #     filter_list.append({"name_full": project_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.project_client.List(
                        lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.Project(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving project_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          project_name: str = None,
                          project_name_full: str = None,
                          iri: str = None,) -> str:
        if project_name is not None:
            filter_dict = {"name": project_name}
        elif project_name_full is not None:
            filter_dict = {"name_full": project_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.project_client.List(
                    lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving project_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].project_id
            else:
                raise ValueError(f"Error retrieving project_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.project_client.List(lara_django_projects_pb2.ProjectListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.project_client.List(
                lara_django_projects_pb2.ProjectListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.project_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.project_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.project_full_client.List(
                lara_django_projects_pb2.ProjectFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.project_full_client.List(
                lara_django_projects_pb2.ProjectFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, project : projects_dm.Project = None) -> None:
        try:
            await self.project_client.Update(
                lara_django_projects_pb2.ProjectRequest(**project.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating project_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.project_client.Destroy(lara_django_projects_pb2.ProjectDestroyRequest(project_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting project_id: {e}")

#_________________  Experiment  ______________________


class ExperimentInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.experiment_class_client = (
        #     lara_django_projects_pb2_grpc.ExperimentclassByIRIControllerStub(channel)
        # )
        
        self.experiment_client = lara_django_projects_pb2_grpc.ExperimentControllerStub(channel)

        # self.experiment_full_client = lara_django_projects_pb2_grpc.ExperimentFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  experiments:  list[projects_dm.Experiment] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.Experiment]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # experimentclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if experiment_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.experiment_class_client.Retrieve(
        #         lara_django_projects_pb2.ExperimentclassRetrieveRequest(iri=experiment_class_iri)
        #     )
        #     experimentclass_id = res.experimentclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving experimentclass_id: {e}")
        # for experiment in experiments:
        #     experiment.namespace = self.namespace_id
        #     experiment.experiment_class = experimentclass_id

        try:
            create_coroutines = ( self.experiment_client.Create(lara_django_projects_pb2.ExperimentRequest(**experiment.model_dump())) for experiment in experiments )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experiment_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating experiment: {e}")

    @export_file
    async def retrieve(
        self, 
        experiment_id: str = None,
        experiment_name: str = None,
        #experiment_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.Experiment]:
        filter_list = []
        results_list = []
        if  experiment_id is not None:
            try:
                res =  await self.experiment_client.Retrieve(
                    lara_django_projects_pb2.ExperimentRetrieveRequest(experiment_id=experiment_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving experiment_id: {e}")

        if experiment_name is not None:
            filter_list.append({"name": experiment_name})
        # if experiment_name_full is not None:
        #     filter_list.append({"name_full": experiment_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experiment_client.List(
                        lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.Experiment(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving experiment_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          experiment_name: str = None,
                          experiment_name_full: str = None,
                          iri: str = None,) -> str:
        if experiment_name is not None:
            filter_dict = {"name": experiment_name}
        elif experiment_name_full is not None:
            filter_dict = {"name_full": experiment_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experiment_client.List(
                    lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving experiment_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].experiment_id
            else:
                raise ValueError(f"Error retrieving experiment_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.experiment_client.List(lara_django_projects_pb2.ExperimentListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experiment_client.List(
                lara_django_projects_pb2.ExperimentListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experiment_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.experiment_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experiment_full_client.List(
                lara_django_projects_pb2.ExperimentFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experiment_full_client.List(
                lara_django_projects_pb2.ExperimentFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, experiment : projects_dm.Experiment = None) -> None:
        try:
            await self.experiment_client.Update(
                lara_django_projects_pb2.ExperimentRequest(**experiment.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating experiment_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.experiment_client.Destroy(lara_django_projects_pb2.ExperimentDestroyRequest(experiment_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting experiment_id: {e}")

#_________________  ExperimentsSubset  ______________________


class ExperimentsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.experimentselection_class_client = (
        #     lara_django_projects_pb2_grpc.ExperimentsSubsetclassByIRIControllerStub(channel)
        # )
        
        self.experimentselection_client = lara_django_projects_pb2_grpc.ExperimentsSubsetControllerStub(channel)

        # self.experimentselection_full_client = lara_django_projects_pb2_grpc.ExperimentsSubsetFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  experimentselections:  list[projects_dm.ExperimentsSubset] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ExperimentsSubset]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # experimentselectionclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if experimentselection_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.experimentselection_class_client.Retrieve(
        #         lara_django_projects_pb2.ExperimentsSubsetclassRetrieveRequest(iri=experimentselection_class_iri)
        #     )
        #     experimentselectionclass_id = res.experimentselectionclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving experimentselectionclass_id: {e}")
        # for experimentselection in experimentselections:
        #     experimentselection.namespace = self.namespace_id
        #     experimentselection.experimentselection_class = experimentselectionclass_id

        try:
            create_coroutines = ( self.experimentselection_client.Create(lara_django_projects_pb2.ExperimentsSubsetRequest(**experimentselection.model_dump())) for experimentselection in experimentselections )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experimentselection_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating experimentselection: {e}")

    @export_file
    async def retrieve(
        self, 
        experimentselection_id: str = None,
        experimentselection_name: str = None,
        #experimentselection_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ExperimentsSubset]:
        filter_list = []
        results_list = []
        if  experimentselection_id is not None:
            try:
                res =  await self.experimentselection_client.Retrieve(
                    lara_django_projects_pb2.ExperimentsSubsetRetrieveRequest(experimentselection_id=experimentselection_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving experimentselection_id: {e}")

        if experimentselection_name is not None:
            filter_list.append({"name": experimentselection_name})
        # if experimentselection_name_full is not None:
        #     filter_list.append({"name_full": experimentselection_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentselection_client.List(
                        lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ExperimentsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving experimentselection_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          experimentselection_name: str = None,
                          experimentselection_name_full: str = None,
                          iri: str = None,) -> str:
        if experimentselection_name is not None:
            filter_dict = {"name": experimentselection_name}
        elif experimentselection_name_full is not None:
            filter_dict = {"name_full": experimentselection_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentselection_client.List(
                    lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving experimentselection_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].experimentselection_id
            else:
                raise ValueError(f"Error retrieving experimentselection_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.experimentselection_client.List(lara_django_projects_pb2.ExperimentsSubsetListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experimentselection_client.List(
                lara_django_projects_pb2.ExperimentsSubsetListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experimentselection_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.experimentselection_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experimentselection_full_client.List(
                lara_django_projects_pb2.ExperimentsSubsetFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experimentselection_full_client.List(
                lara_django_projects_pb2.ExperimentsSubsetFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, experimentselection : projects_dm.ExperimentsSubset = None) -> None:
        try:
            await self.experimentselection_client.Update(
                lara_django_projects_pb2.ExperimentsSubsetRequest(**experimentselection.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating experimentselection_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.experimentselection_client.Destroy(lara_django_projects_pb2.ExperimentsSubsetDestroyRequest(experimentselection_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting experimentselection_id: {e}")

#_________________  ProjectsSubset  ______________________


class ProjectsSubsetInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectselection_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectselectionclassByIRIControllerStub(channel)
        # )
        
        self.projectselection_client = lara_django_projects_pb2_grpc.ProjectselectionControllerStub(channel)

        # self.projectselection_full_client = lara_django_projects_pb2_grpc.ProjectselectionFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  projectselections:  list[projects_dm.ProjectsSubset] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ProjectsSubset]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # projectselectionclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectselection_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectselection_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectselectionclassRetrieveRequest(iri=projectselection_class_iri)
        #     )
        #     projectselectionclass_id = res.projectselectionclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving projectselectionclass_id: {e}")
        # for projectselection in projectselections:
        #     projectselection.namespace = self.namespace_id
        #     projectselection.projectselection_class = projectselectionclass_id

        try:
            create_coroutines = ( self.projectselection_client.Create(lara_django_projects_pb2.ProjectselectionRequest(**projectselection.model_dump())) for projectselection in projectselections )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectselection_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating projectselection: {e}")

    @export_file
    async def retrieve(
        self, 
        projectselection_id: str = None,
        projectselection_name: str = None,
        #projectselection_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectsSubset]:
        filter_list = []
        results_list = []
        if  projectselection_id is not None:
            try:
                res =  await self.projectselection_client.Retrieve(
                    lara_django_projects_pb2.ProjectselectionRetrieveRequest(projectselection_id=projectselection_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving projectselection_id: {e}")

        if projectselection_name is not None:
            filter_list.append({"name": projectselection_name})
        # if projectselection_name_full is not None:
        #     filter_list.append({"name_full": projectselection_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectselection_client.List(
                        lara_django_projects_pb2.ProjectselectionListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectsSubset(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving projectselection_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          projectselection_name: str = None,
                          projectselection_name_full: str = None,
                          iri: str = None,) -> str:
        if projectselection_name is not None:
            filter_dict = {"name": projectselection_name}
        elif projectselection_name_full is not None:
            filter_dict = {"name_full": projectselection_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectselection_client.List(
                    lara_django_projects_pb2.ProjectselectionListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving projectselection_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].projectselection_id
            else:
                raise ValueError(f"Error retrieving projectselection_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.projectselection_client.List(lara_django_projects_pb2.ProjectselectionListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectselection_client.List(
                lara_django_projects_pb2.ProjectselectionListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectselection_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.projectselection_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectselection_full_client.List(
                lara_django_projects_pb2.ProjectselectionFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectselection_full_client.List(
                lara_django_projects_pb2.ProjectselectionFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, projectselection : projects_dm.ProjectsSubset = None) -> None:
        try:
            await self.projectselection_client.Update(
                lara_django_projects_pb2.ProjectselectionRequest(**projectselection.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating projectselection_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.projectselection_client.Destroy(lara_django_projects_pb2.ProjectselectionDestroyRequest(projectselection_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting projectselection_id: {e}")

#_________________  ProjectCalendar  ______________________


class ProjectCalendarInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectcalendar_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectcalendarclassByIRIControllerStub(channel)
        # )
        
        self.projectcalendar_client = lara_django_projects_pb2_grpc.ProjectcalendarControllerStub(channel)

        # self.projectcalendar_full_client = lara_django_projects_pb2_grpc.ProjectcalendarFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  projectcalendars:  list[projects_dm.ProjectCalendar] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ProjectCalendar]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # projectcalendarclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectcalendar_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectcalendar_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectcalendarclassRetrieveRequest(iri=projectcalendar_class_iri)
        #     )
        #     projectcalendarclass_id = res.projectcalendarclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving projectcalendarclass_id: {e}")
        # for projectcalendar in projectcalendars:
        #     projectcalendar.namespace = self.namespace_id
        #     projectcalendar.projectcalendar_class = projectcalendarclass_id

        try:
            create_coroutines = ( self.projectcalendar_client.Create(lara_django_projects_pb2.ProjectcalendarRequest(**projectcalendar.model_dump())) for projectcalendar in projectcalendars )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectcalendar_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating projectcalendar: {e}")

    @export_file
    async def retrieve(
        self, 
        projectcalendar_id: str = None,
        projectcalendar_name: str = None,
        #projectcalendar_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectCalendar]:
        filter_list = []
        results_list = []
        if  projectcalendar_id is not None:
            try:
                res =  await self.projectcalendar_client.Retrieve(
                    lara_django_projects_pb2.ProjectcalendarRetrieveRequest(projectcalendar_id=projectcalendar_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving projectcalendar_id: {e}")

        if projectcalendar_name is not None:
            filter_list.append({"name": projectcalendar_name})
        # if projectcalendar_name_full is not None:
        #     filter_list.append({"name_full": projectcalendar_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectcalendar_client.List(
                        lara_django_projects_pb2.ProjectcalendarListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectCalendar(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving projectcalendar_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          projectcalendar_name: str = None,
                          projectcalendar_name_full: str = None,
                          iri: str = None,) -> str:
        if projectcalendar_name is not None:
            filter_dict = {"name": projectcalendar_name}
        elif projectcalendar_name_full is not None:
            filter_dict = {"name_full": projectcalendar_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectcalendar_client.List(
                    lara_django_projects_pb2.ProjectcalendarListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving projectcalendar_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].projectcalendar_id
            else:
                raise ValueError(f"Error retrieving projectcalendar_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.projectcalendar_client.List(lara_django_projects_pb2.ProjectcalendarListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectcalendar_client.List(
                lara_django_projects_pb2.ProjectcalendarListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectcalendar_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.projectcalendar_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectcalendar_full_client.List(
                lara_django_projects_pb2.ProjectcalendarFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectcalendar_full_client.List(
                lara_django_projects_pb2.ProjectcalendarFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, projectcalendar : projects_dm.ProjectCalendar = None) -> None:
        try:
            await self.projectcalendar_client.Update(
                lara_django_projects_pb2.ProjectcalendarRequest(**projectcalendar.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating projectcalendar_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.projectcalendar_client.Destroy(lara_django_projects_pb2.ProjectcalendarDestroyRequest(projectcalendar_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting projectcalendar_id: {e}")

#_________________  ExperimentCalendar  ______________________


class ExperimentCalendarInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.experimentcalendar_class_client = (
        #     lara_django_projects_pb2_grpc.ExperimentCalendarclassByIRIControllerStub(channel)
        # )
        
        self.experimentcalendar_client = lara_django_projects_pb2_grpc.ExperimentCalendarControllerStub(channel)

        # self.experimentcalendar_full_client = lara_django_projects_pb2_grpc.ExperimentCalendarFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  experimentcalendars:  list[projects_dm.ExperimentCalendar] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ExperimentCalendar]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # experimentcalendarclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if experimentcalendar_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.experimentcalendar_class_client.Retrieve(
        #         lara_django_projects_pb2.ExperimentCalendarclassRetrieveRequest(iri=experimentcalendar_class_iri)
        #     )
        #     experimentcalendarclass_id = res.experimentcalendarclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving experimentcalendarclass_id: {e}")
        # for experimentcalendar in experimentcalendars:
        #     experimentcalendar.namespace = self.namespace_id
        #     experimentcalendar.experimentcalendar_class = experimentcalendarclass_id

        try:
            create_coroutines = ( self.experimentcalendar_client.Create(lara_django_projects_pb2.ExperimentCalendarRequest(**experimentcalendar.model_dump())) for experimentcalendar in experimentcalendars )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.experimentcalendar_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating experimentcalendar: {e}")

    @export_file
    async def retrieve(
        self, 
        experimentcalendar_id: str = None,
        experimentcalendar_name: str = None,
        #experimentcalendar_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ExperimentCalendar]:
        filter_list = []
        results_list = []
        if  experimentcalendar_id is not None:
            try:
                res =  await self.experimentcalendar_client.Retrieve(
                    lara_django_projects_pb2.ExperimentCalendarRetrieveRequest(experimentcalendar_id=experimentcalendar_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving experimentcalendar_id: {e}")

        if experimentcalendar_name is not None:
            filter_list.append({"name": experimentcalendar_name})
        # if experimentcalendar_name_full is not None:
        #     filter_list.append({"name_full": experimentcalendar_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentcalendar_client.List(
                        lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ExperimentCalendar(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving experimentcalendar_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          experimentcalendar_name: str = None,
                          experimentcalendar_name_full: str = None,
                          iri: str = None,) -> str:
        if experimentcalendar_name is not None:
            filter_dict = {"name": experimentcalendar_name}
        elif experimentcalendar_name_full is not None:
            filter_dict = {"name_full": experimentcalendar_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.experimentcalendar_client.List(
                    lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving experimentcalendar_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].experimentcalendar_id
            else:
                raise ValueError(f"Error retrieving experimentcalendar_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.experimentcalendar_client.List(lara_django_projects_pb2.ExperimentCalendarListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.experimentcalendar_client.List(
                lara_django_projects_pb2.ExperimentCalendarListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.experimentcalendar_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.experimentcalendar_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.experimentcalendar_full_client.List(
                lara_django_projects_pb2.ExperimentCalendarFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.experimentcalendar_full_client.List(
                lara_django_projects_pb2.ExperimentCalendarFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, experimentcalendar : projects_dm.ExperimentCalendar = None) -> None:
        try:
            await self.experimentcalendar_client.Update(
                lara_django_projects_pb2.ExperimentCalendarRequest(**experimentcalendar.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating experimentcalendar_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.experimentcalendar_client.Destroy(lara_django_projects_pb2.ExperimentCalendarDestroyRequest(experimentcalendar_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting experimentcalendar_id: {e}")

#_________________  ProjectSynchronisation  ______________________


class ProjectSynchronisationInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectsynchronisation_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectSynchronisationclassByIRIControllerStub(channel)
        # )
        
        self.projectsynchronisation_client = lara_django_projects_pb2_grpc.ProjectSynchronisationControllerStub(channel)

        # self.projectsynchronisation_full_client = lara_django_projects_pb2_grpc.ProjectSynchronisationFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  projectsynchronisations:  list[projects_dm.ProjectSynchronisation] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ProjectSynchronisation]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # projectsynchronisationclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectsynchronisation_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectsynchronisation_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectSynchronisationclassRetrieveRequest(iri=projectsynchronisation_class_iri)
        #     )
        #     projectsynchronisationclass_id = res.projectsynchronisationclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving projectsynchronisationclass_id: {e}")
        # for projectsynchronisation in projectsynchronisations:
        #     projectsynchronisation.namespace = self.namespace_id
        #     projectsynchronisation.projectsynchronisation_class = projectsynchronisationclass_id

        try:
            create_coroutines = ( self.projectsynchronisation_client.Create(lara_django_projects_pb2.ProjectSynchronisationRequest(**projectsynchronisation.model_dump())) for projectsynchronisation in projectsynchronisations )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectsynchronisation_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating projectsynchronisation: {e}")

    @export_file
    async def retrieve(
        self, 
        projectsynchronisation_id: str = None,
        projectsynchronisation_name: str = None,
        #projectsynchronisation_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectSynchronisation]:
        filter_list = []
        results_list = []
        if  projectsynchronisation_id is not None:
            try:
                res =  await self.projectsynchronisation_client.Retrieve(
                    lara_django_projects_pb2.ProjectSynchronisationRetrieveRequest(projectsynchronisation_id=projectsynchronisation_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving projectsynchronisation_id: {e}")

        if projectsynchronisation_name is not None:
            filter_list.append({"name": projectsynchronisation_name})
        # if projectsynchronisation_name_full is not None:
        #     filter_list.append({"name_full": projectsynchronisation_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsynchronisation_client.List(
                        lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectSynchronisation(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving projectsynchronisation_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          projectsynchronisation_name: str = None,
                          projectsynchronisation_name_full: str = None,
                          iri: str = None,) -> str:
        if projectsynchronisation_name is not None:
            filter_dict = {"name": projectsynchronisation_name}
        elif projectsynchronisation_name_full is not None:
            filter_dict = {"name_full": projectsynchronisation_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsynchronisation_client.List(
                    lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving projectsynchronisation_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].projectsynchronisation_id
            else:
                raise ValueError(f"Error retrieving projectsynchronisation_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.projectsynchronisation_client.List(lara_django_projects_pb2.ProjectSynchronisationListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectsynchronisation_client.List(
                lara_django_projects_pb2.ProjectSynchronisationListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectsynchronisation_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.projectsynchronisation_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectsynchronisation_full_client.List(
                lara_django_projects_pb2.ProjectSynchronisationFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectsynchronisation_full_client.List(
                lara_django_projects_pb2.ProjectSynchronisationFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, projectsynchronisation : projects_dm.ProjectSynchronisation = None) -> None:
        try:
            await self.projectsynchronisation_client.Update(
                lara_django_projects_pb2.ProjectSynchronisationRequest(**projectsynchronisation.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating projectsynchronisation_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.projectsynchronisation_client.Destroy(lara_django_projects_pb2.ProjectSynchronisationDestroyRequest(projectsynchronisation_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting projectsynchronisation_id: {e}")

#_________________  ProjectSyncStatus  ______________________


class ProjectSyncStatusInterface:
    def __init__(self, channel: grpc.Channel = None, default_namespace_uri : str = None) -> None:
        self.default_namespace_uri = None
        self.default_namespace_id = None

        if default_namespace_uri is not None:
            self.default_namespace_uri = default_namespace_uri
        
        self.namespace_if = base_if.NamespaceInterface(channel)

        # self.projectsyncstatus_class_client = (
        #     lara_django_projects_pb2_grpc.ProjectSyncStatusclassByIRIControllerStub(channel)
        # )
        
        self.projectsyncstatus_client = lara_django_projects_pb2_grpc.ProjectSyncStatusControllerStub(channel)

        # self.projectsyncstatus_full_client = lara_django_projects_pb2_grpc.ProjectSyncStatusFullControllerStub(
        #     channel
        # )

    @import_file(relation_resolver=lambda x: x)
    async def create(self,  projectsyncstatus:  list[projects_dm.ProjectSyncStatus] = None,  ids_only: bool = False, namespace_uri: str = None) -> Union[list[str], list[projects_dm.ProjectSyncStatus]]:
        # TODO: only retrieve default_namespace_id if not already retrieved and namespace_uri is None
        self.namespace_id = None
        # projectsyncstatusclass_id = None
        if namespace_uri is None and self.default_namespace_uri is not None:
            namespace_uri = self.default_namespace_uri
        if namespace_uri is None:
            raise ValueError("No namespace URI is given.")
        try:
            self.namespace_id = await self.namespace_if.retrieve_id(namespace_uri=namespace_uri)
        except Exception as e:
            logging.error(f"Error retrieving namespace_id: {e}")
        
        # some sample code for retrieving a class IRI and adding namespace and class to the model
        # if projectsyncstatus_class_iri is None:
        #     raise ValueError("No sample class IRI is given.")
        # try:
        #     res = await self.projectsyncstatus_class_client.Retrieve(
        #         lara_django_projects_pb2.ProjectSyncStatusclassRetrieveRequest(iri=projectsyncstatus_class_iri)
        #     )
        #     projectsyncstatusclass_id = res.projectsyncstatusclass_id 
        # except Exception as e:
        #     logging.error(f"Error retrieving projectsyncstatusclass_id: {e}")
        # for projectsyncstatus in projectsyncstatuss:
        #     projectsyncstatus.namespace = self.namespace_id
        #     projectsyncstatus.projectsyncstatus_class = projectsyncstatusclass_id

        try:
            create_coroutines = ( self.projectsyncstatus_client.Create(lara_django_projects_pb2.ProjectSyncStatusRequest(**projectsyncstatus.model_dump())) for projectsyncstatus in projectsyncstatus )
            res = await asyncio.gather(*create_coroutines)
            if ids_only:
                return [item.projectsyncstatus_id for item in res]
            else:
                return res

        except Exception as e:
            logging.error(f"Error creating projectsyncstatus: {e}")

    @export_file
    async def retrieve(
        self, 
        projectsyncstatus_id: str = None,
        projectsyncstatus_name: str = None,
        #projectsyncstatus_name_full: str = None,
        filter_dict: dict = None,
        raw : bool = False
        ) -> list[projects_dm.ProjectSyncStatus]:
        filter_list = []
        results_list = []
        if  projectsyncstatus_id is not None:
            try:
                res =  await self.projectsyncstatus_client.Retrieve(
                    lara_django_projects_pb2.ProjectSyncStatusRetrieveRequest(projectsyncstatus_id=projectsyncstatus_id) )
                if raw:
                    results_list.append(res)
                else:
                    results_list.append( projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True)) )
            except Exception as e:
                logging.error(f"Error retrieving projectsyncstatus_id: {e}")

        if projectsyncstatus_name is not None:
            filter_list.append({"name": projectsyncstatus_name})
        # if projectsyncstatus_name_full is not None:
        #     filter_list.append({"name_full": projectsyncstatus_name_full})
        if filter_dict is not None:
            filter_list.append(filter_dict)

        for filter_dict in filter_list:
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsyncstatus_client.List(
                        lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
                      )
                if raw:
                      results_list += res.results
                else:
                    # a queue could be used here to speed up the retrieval
                    results = res.results
                    results_list += [ projects_dm.ProjectSyncStatus(**MessageToDict(res, preserving_proto_field_name=True)) for res in results ]
            except Exception as e:
                logging.error(f"Error retrieving projectsyncstatus_name: {e}")

        return results_list

    #@id_cache
    async def retrieve_id(self, 
                          projectsyncstatus_name: str = None,
                          projectsyncstatus_name_full: str = None,
                          iri: str = None,) -> str:
        if projectsyncstatus_name is not None:
            filter_dict = {"name": projectsyncstatus_name}
        elif projectsyncstatus_name_full is not None:
            filter_dict = {"name_full": projectsyncstatus_name_full}
        elif iri is not None:
            filter_dict = {"iri": iri}
            metadata = (("filters", (json.dumps(filter_dict))),)
            try:
                res = await self.projectsyncstatus_client.List(
                    lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
                )
                results = res.results
            except Exception as e:
                logging.error(f"Error retrieving projectsyncstatus_name: {e}")
            if len(results) > 0 and len(results) < 2:
                return results[0].projectsyncstatus_id
            else:
                raise ValueError(f"Error retrieving projectsyncstatus_id - no or too many results found.")
            
        
    async def list(self, filter_dict: dict = None, ids_only: bool = False) -> list[str]:
        if filter_dict is None:
            res = await self.projectsyncstatus_client.List(lara_django_projects_pb2.ProjectSyncStatusListRequest())
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            res = await self.projectsyncstatus_client.List(
                lara_django_projects_pb2.ProjectSyncStatusListRequest(), metadata=metadata
            )
        if res is not None and ids_only:
            return [item.projectsyncstatus_id for item in res.results]
        else:
            return res.results
            

    async def list_full(self, filter_dict: dict = None) :
        if self.projectsyncstatus_full_client is None:
            raise ValueError("No full client available.")
        if filter_dict is None:
            return await self.projectsyncstatus_full_client.List(
                lara_django_projects_pb2.ProjectSyncStatusFullListRequest()
            )
        else:
            metadata = (("filters", (json.dumps(filter_dict))),)
            return await self.projectsyncstatus_full_client.List(
                lara_django_projects_pb2.ProjectSyncStatusFullListRequest(), metadata=metadata
            )

    @import_file(relation_resolver=lambda x: x)
    # @update_image(stub,  file_chunk_method=None)
    async def update(self, projectsyncstatus : projects_dm.ProjectSyncStatus = None) -> None:
        try:
            await self.projectsyncstatus_client.Update(
                lara_django_projects_pb2.ProjectSyncStatusRequest(**projectsyncstatus.model_dump()
            ))
        except Exception as e:
            logging.error(f"Error updating projectsyncstatus_id: {e}")

    async def delete(self, id_list: list[str] = None, filter_dict: dict = None) -> None:
        if filter_dict is not None:
            id_list = await self.list(filter_dict, ids_only=True)
    
        try:
            delete_coroutines = ( self.projectsyncstatus_client.Destroy(lara_django_projects_pb2.ProjectSyncStatusDestroyRequest(projectsyncstatus_id=id)) for id in id_list )
            await asyncio.gather(*delete_coroutines)
            
        except Exception as e:
            logging.error(f"Error deleting projectsyncstatus_id: {e}")

