from datetime import datetime, timedelta

from modules.DatabaseModule.DBManager import DBManager
from modules.DatabaseModule.DBManagerTeraServiceAccess import DBManagerTeraServiceAccess
from opentera.db.models.TeraUser import TeraUser
from opentera.db.models.TeraUserGroup import TeraUserGroup
from opentera.db.models.TeraUserUserGroup import TeraUserUserGroup
from opentera.db.models.TeraParticipant import TeraParticipant
from opentera.db.models.TeraParticipantGroup import TeraParticipantGroup
from opentera.db.models.TeraService import TeraService
from opentera.db.models.TeraDevice import TeraDevice
from opentera.db.models.TeraProject import TeraProject
from opentera.db.models.TeraSite import TeraSite
from opentera.db.models.TeraSession import TeraSession, TeraSessionStatus
from opentera.db.models.TeraSessionType import TeraSessionType
from opentera.db.models.TeraTestType import TeraTestType
from opentera.db.models.TeraTestInvitation import TeraTestInvitation
from opentera.db.models.TeraServiceAccess import TeraServiceAccess
from opentera.db.models.TeraServiceRole import TeraServiceRole
from opentera.db.models.TeraAsset import TeraAsset
from tests.opentera.db.models.BaseModelsTest import BaseModelsTest


class DBManagerTeraServiceAccessTest(BaseModelsTest):

    def _create_service_with_no_access(self) -> TeraService:

        # Since service keys are unique, if service already exists, return it
        service = TeraService.get_service_by_key('NoAccess')
        if service:
            return service

        service = TeraService()
        # service.id_service = 0 # This is generated by the DB
        # service.service_uuid = '00000000-0000-0000-0000-000000000000' # This is generated by the DB
        service.service_name = 'No Access'
        service.service_key = 'NoAccess'
        service.service_hostname = 'localhost'
        service.service_port = 8080
        service.service_endpoint = '/noaccess'
        service.service_clientendpoint = '/noaccess'
        service.service_endpoint_user = '/noaccess'
        service.service_endpoint_participant = '/noaccess'
        service.service_endpoint_device = '/noaccess'
        service.service_enabled = True
        service.service_system = False
        service.service_editable_config = False
        service.service_default_config = '{}'
        service.service_has_assets = False
        service.service_has_tests = False
        TeraService.insert(service)
        return service

    def test_service_get_accessible_devices_ids_and_uuids(self):
        """
        This will test at the same time get_accessible_devices and get_accessible_devices_ids/uuids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            devices_ids : set[int] = set(service_access.get_accessible_devices_ids())
            devices_uuids : set[str] = set(service_access.get_accessible_devices_uuids())

            all_devices = TeraDevice.query.all()
            accessible_devices = set()
            for device in all_devices:
                for project in device.device_projects:
                    if project.id_project in service_access.get_accessible_projects_ids():
                        accessible_devices.add(device.id_device)

            self.assertEqual(len(devices_ids), len(accessible_devices))
            self.assertEqual(len(devices_uuids), len(devices_ids))
            self.assertEqual(devices_ids, accessible_devices)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_devices_ids()), 0)

    def test_service_get_accessible_projects_ids(self):
        """
        This will test at the same time get_accessible_projects and get_accessible_projects_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            projects_ids = set(service_access.get_accessible_projects_ids())

            all_projects: list[TeraProject] = TeraProject.query.all()
            accessible_projects = set()
            for project in all_projects:
                for project_service in project.project_services:
                    if project_service.id_service == service.id_service:
                        accessible_projects.add(project.id_project)
            self.assertEqual(len(projects_ids), len(accessible_projects))
            self.assertEqual(projects_ids, accessible_projects)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_projects_ids()), 0)

    def test_service_get_accessible_sessions_ids(self):
        """
        This will test at the same time get_accessible_sessions and get_accessible_sessions_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            sessions_ids = set(service_access.get_accessible_sessions_ids())

            all_sessions = TeraSession.query.all()
            accessible_sessions = set()

            for session in all_sessions:
                # Creator
                if session.id_creator_service == service.id_service:
                    accessible_sessions.add(session.id_session)

                session_type : TeraSessionType = TeraSessionType.query.get(session.id_session_type)

                # Same service ?
                if session_type.id_service == service.id_service:
                    accessible_sessions.add(session.id_session)
                    continue

                # Secondary services
                for secondary_service in session_type.session_type_secondary_services:
                    if secondary_service.id_service == service.id_service:
                        accessible_sessions.add(session.id_session)
                        break

            self.assertEqual(len(sessions_ids), len(accessible_sessions))
            self.assertEqual(sessions_ids, accessible_sessions)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_sessions_ids()), 0)

    def test_service_get_accessible_sites_id(self):
        """
        This will test at the same time get_accessible_sites and get_accessible_sites_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            sites_ids = set(service_access.get_accessible_sites_ids())

            all_sites = TeraSite.query.all()
            accessible_sites = set()
            for site in all_sites:
                for project in site.site_projects:
                    if project.id_project in service_access.get_accessible_projects_ids():
                        accessible_sites.add(site.id_site)
            self.assertEqual(len(sites_ids), len(accessible_sites))
            self.assertEqual(sites_ids, accessible_sites)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_sites_ids()), 0)

    def test_service_get_accessible_participants_id(self):
        """
        This will test at the same time get_accessible_participants and get_accessible_participants_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            participants_ids = set(service_access.get_accessible_participants_ids())

            all_participants = TeraParticipant.query.all()
            accessible_participants = set()
            for participant in all_participants:
                if participant.id_project in service_access.get_accessible_projects_ids():
                    accessible_participants.add(participant.id_participant)
            self.assertEqual(len(participants_ids), len(accessible_participants))
            self.assertEqual(participants_ids, accessible_participants)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_participants_ids()), 0)

    def test_service_get_accessible_participant_groups_id(self):
        """
        This will test at the same time get_accessible_participant_groups and get_accessible_participant_groups_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access: DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            participant_groups_ids = set(service_access.get_accessible_participants_groups_ids())

            all_participant_groups = TeraParticipantGroup.query.all()
            accessible_participant_groups = set()
            for participant_group in all_participant_groups:
                if participant_group.id_project in service_access.get_accessible_projects_ids():
                    accessible_participant_groups.add(participant_group.id_participant_group)
            self.assertEqual(len(participant_groups_ids), len(accessible_participant_groups))
            self.assertEqual(participant_groups_ids, accessible_participant_groups)

            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_participants_groups_ids()), 0)

    def test_service_get_accessible_users_ids(self):
        """
        This will test at the same time get_accessible_users and get_accessible_users_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            users_ids = set(service_access.get_accessible_users_ids())

            all_users = TeraUser.query.all()
            accessible_users = set()

            service_projects_ids = [project.id_project for project in service.service_projects]
            service_site_ids = [site.id_site for site in service.service_sites]

            for user in all_users:
                if user.user_superadmin:
                    accessible_users.add(user.id_user)
                    continue

                teraserver_service = TeraService.get_openteraserver_service()

                for user_group in user.user_user_groups:
                    for service_role in user_group.user_group_services_roles:
                        if service_role.id_service == teraserver_service.id_service:
                            # Add users that have a role in a project accessible by the service
                            if service_role.id_project in service_projects_ids :
                                accessible_users.add(user.id_user)
                            # Add users that have a role in a site accessible by the service
                            if service_role.id_site in service_site_ids :
                                accessible_users.add(user.id_user)

            self.assertEqual(len(users_ids), len(accessible_users))
            self.assertEqual(users_ids, accessible_users)

            # Test with a service with no access
            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_users_ids()), 0)

    def test_service_get_accessible_usergroup_ids(self):
        """
        This will test at the same time get_accessible_usergroups and get_accessible_usergroups_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            usergroups_ids = set(service_access.get_accessible_usergroups_ids())

            all_usergroups = TeraUserGroup.query.all()
            accessible_usergroups = set()

            service_projects_ids = [project.id_project for project in service.service_projects]
            service_site_ids = [site.id_site for site in service.service_sites]

            teraserver_service = TeraService.get_openteraserver_service()

            for usergroup in all_usergroups:
                for service_role in usergroup.user_group_services_roles:
                    # TODO More permissive ?
                    #if service_role.id_service == teraserver_service.id_service or \
                    #    service_role.id_service == service.id_service:
                    if service_role.id_service == service.id_service:
                        # Add usergroups that have a role in a project accessible by the service
                        if service_role.id_project in service_projects_ids:
                            accessible_usergroups.add(usergroup.id_user_group)
                        # Add usergroups that have a role in a site accessible by the service
                        if service_role.id_site in service_site_ids:
                            accessible_usergroups.add(usergroup.id_user_group)

            self.assertEqual(len(usergroups_ids), len(accessible_usergroups))
            self.assertEqual(usergroups_ids, accessible_usergroups)

            # Test with a service with no access
            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_usergroups_ids()), 0)

    def test_service_get_accessible_sessions_types_ids(self):
        """
        This will test at the same time get_accessible_session_types and get_accessible_session_types_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            session_types_ids = set(service_access.get_accessible_sessions_types_ids())

            all_session_types = TeraSessionType.query.all()
            accessible_session_types = set()
            for session_type in all_session_types:
                if session_type.id_service == service.id_service:
                    accessible_session_types.add(session_type.id_session_type)
            self.assertEqual(len(session_types_ids), len(accessible_session_types))
            self.assertEqual(session_types_ids, accessible_session_types)

            # Test with a service with no access
            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_sessions_types_ids()), 0)

    def test_service_get_accessible_tests_types_ids(self):
        """
        This will test at the same time get_accessible_tests_types and get_accessible_tests_types_ids.
        """
        with self._flask_app.app_context():
            service =  TeraService.get_service_by_key('VideoRehabService')
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            test_types_ids = set(service_access.get_accessible_tests_types_ids())

            all_test_types = TeraTestType.query.all()
            accessible_test_types = set()
            for test_type in all_test_types:
                if test_type.id_service == service.id_service:
                    accessible_test_types.add(test_type.id_test_type)
            self.assertEqual(len(test_types_ids), len(accessible_test_types))
            self.assertEqual(test_types_ids, accessible_test_types)

            # Test with a service with no access
            service = self._create_service_with_no_access()
            self.assertIsNotNone(service)
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertEqual(len(service_access.get_accessible_tests_types_ids()), 0)


    def test_service_get_accessible_tests_types_ids_for_device(self):
        """
        This will test at the same time get_accessible_tests_types_for_device and get_accessible_tests_types_ids_for_device.
        """
        with self._flask_app.app_context():

            all_devices = TeraDevice.query.all()
            for device in all_devices:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)

                test_types_service_ids = service_access.get_accessible_tests_types_ids()
                test_types_ids = set(service_access.get_accessible_tests_types_ids_for_device(device.id_device))

                for id_test_type in test_types_ids:
                    self.assertTrue(id_test_type in test_types_service_ids)

                # Test with a service with no access
                service = self._create_service_with_no_access()
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                self.assertEqual(len(service_access.get_accessible_tests_types_ids_for_device(device.id_device)), 0)

    def test_service_get_accessible_tests_types_ids_for_participant(self):
        """
        This will test at the same time get_accessible_tests_types_for_participant and get_accessible_tests_types_ids_for_participant.
        """
        with self._flask_app.app_context():

            all_participants = TeraParticipant.query.all()
            for participant in all_participants:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)

                test_types_service_ids = service_access.get_accessible_tests_types_ids()
                test_types_ids = set(service_access.get_accessible_tests_types_ids_for_participant(participant.id_participant))

                for id_test_type in test_types_ids:
                    self.assertTrue(id_test_type in test_types_service_ids)

                # Test with a service with no access
                service = self._create_service_with_no_access()
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                self.assertEqual(len(service_access.get_accessible_tests_types_ids_for_participant(participant.id_participant)), 0)

    def test_service_get_accesible_tests_types_ids_for_user(self):
        """
        This will test at the same time get_accessible_tests_types_for_user and get_accessible_tests_types_ids_for_user.
        """
        with self._flask_app.app_context():

            all_users = TeraUser.query.all()
            for user in all_users:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)

                test_types_service_ids = service_access.get_accessible_tests_types_ids()
                test_types_ids = set(service_access.get_accessible_tests_types_ids_for_user(user.id_user))

                for id_test_type in test_types_ids:
                    self.assertTrue(id_test_type in test_types_service_ids)

                # Test with a service with no access
                service = self._create_service_with_no_access()
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                self.assertEqual(len(service_access.get_accessible_tests_types_ids_for_user(user.id_user)), 0)

    def test_service_get_site_role(self):
        """
        This will test get_site_role.
        """
        with self._flask_app.app_context():

            all_users = TeraUser.query.all()
            all_sites = TeraSite.query.all()

            for user in all_users:

                for site in all_sites:
                    service =  TeraService.get_service_by_key('VideoRehabService')
                    self.assertIsNotNone(service)
                    service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)

                    site_role = service_access.get_site_role(site_id = site.id_site, uuid_user = user.user_uuid)

                    teraserver_service = TeraService.get_openteraserver_service()

                    if site.id_site in service_access.get_accessible_sites_ids():
                        if user.user_superadmin:
                            self.assertEqual(site_role, 'admin')
                            continue

                        queried_role = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                                .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                                .join(TeraSite, TeraServiceRole.id_site == TeraSite.id_site) \
                                                                .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                                .filter(TeraSite.id_site == site.id_site) \
                                                                .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                                .with_entities(TeraServiceRole).first()


                        # Query role for project if not found for site, if users have access to a project, they need to be automatically granted access to the site
                        if not queried_role:
                            queried_roles = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                                .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                                .join(TeraProject, TeraServiceRole.id_project == TeraProject.id_project) \
                                                                .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                                .filter(TeraProject.id_site == site.id_site) \
                                                                .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                                .with_entities(TeraServiceRole).all()

                            if len(queried_roles) > 0:
                                # Inherited has always the user role
                                queried_role = TeraServiceRole()
                                queried_role.id_service = teraserver_service.id_service
                                queried_role.service_role_name='user'
                    else:
                        queried_role = None

                    queried_role_name = queried_role.service_role_name if queried_role else None

                    self.assertEqual(site_role, queried_role_name)

    def test_service_get_project_role(self):
        """
        This will test get_project_role.
        """
        with self._flask_app.app_context():

            all_users = TeraUser.query.all()
            all_projects = TeraProject.query.all()

            for user in all_users:
                for project in all_projects:
                    service =  TeraService.get_service_by_key('VideoRehabService')
                    self.assertIsNotNone(service)
                    service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)

                    project_role = service_access.get_project_role(project_id = project.id_project, uuid_user = user.user_uuid)

                    teraserver_service = TeraService.get_openteraserver_service()
                    queried_role = None
                    if project.id_project in service_access.get_accessible_projects_ids():
                        if user.user_superadmin:
                            self.assertEqual(project_role, 'admin')
                            continue

                        queried_roles = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                                .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                                .join(TeraProject, TeraServiceRole.id_project == TeraProject.id_project) \
                                                                .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                                .filter(TeraProject.id_project == project.id_project) \
                                                                .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                                .with_entities(TeraServiceRole).all()

                        # Keep admin as priority
                        for role in queried_roles:
                            if role.service_role_name == 'admin':
                                queried_role = role
                                break
                            elif not queried_role:
                                queried_role = role

                        # Query role for site might override project role
                        queried_roles = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                            .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                            .join(TeraSite, TeraServiceRole.id_site == TeraSite.id_site) \
                                                            .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                            .filter(TeraSite.id_site == project.id_site) \
                                                            .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                            .with_entities(TeraServiceRole).all()
                        # Keep admin as priority
                        for role in queried_roles:
                            if role.service_role_name == 'admin' :
                                queried_role = role
                                break
                            elif not queried_role:
                                queried_role = role
                    else:
                        queried_role = None


                    queried_role_name = queried_role.service_role_name if queried_role else None

                    self.assertEqual(project_role, queried_role_name)

    def test_service_get_user_with_uuid(self):
        """
        This will test get_user_with_uuid.
        """
        with self._flask_app.app_context():

            all_users = TeraUser.query.all()
            for user in all_users:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                my_user = service_access.get_user_with_uuid(uuid_user = user.user_uuid)
                # if (user.user_superadmin):
                #     self.assertIsNone(my_user)
                # else:
                if user.id_user in service_access.get_accessible_users_ids():
                    self.assertEqual(my_user.id_user, user.id_user)
                else:
                    self.assertIsNone(my_user)

    def test_service_query_sites_for_user(self):
        """
        This will test query_sites_ids_for_user.
        """
        with self._flask_app.app_context():

            all_users = TeraUser.query.all()
            for user in all_users:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                sites = set(service_access.query_sites_for_user(user_id = user.id_user))

                if user.user_superadmin:
                    self.assertEqual(len(sites), 1)
                else:
                    teraserver_service = TeraService.get_openteraserver_service()
                    queried_sites = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                            .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                            .join(TeraSite, TeraServiceRole.id_site == TeraSite.id_site) \
                                                            .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                            .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                            .with_entities(TeraSite).all()

                    queried_projects = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                                                            .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                                                            .join(TeraProject, TeraServiceRole.id_project == TeraProject.id_project) \
                                                            .filter(TeraUserUserGroup.id_user == user.id_user) \
                                                            .filter(TeraServiceRole.id_service == teraserver_service.id_service) \
                                                            .with_entities(TeraProject).all()

                    for project in queried_projects:
                        queried_sites.extend([project.project_site])


                    self.assertEqual(len(set(sites)), len(set(queried_sites)))

    def test_service_query_asset(self):
        """
        This will test query_asset.
        """
        with self._flask_app.app_context():

            all_assets = TeraAsset.query.all()
            for asset in all_assets:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                my_assets = service_access.query_asset(asset_id = asset.id_asset)

                # TODO Can only access assets produce by the service ?
                # TODO Or all available assets in the project ?
                # TODO Association to project is weak and depends on participants in the session

    def test_service_query_session(self):
        """
        This will test query_session.
        """
        with self._flask_app.app_context():

            all_sessions = TeraSession.query.all()
            for session in all_sessions:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                my_sessions = service_access.query_session(session_id = session.id_session)

                # TODO Can only access sessions produce by the service ?
                # TODO Or all available sessions in the project ?
                # TODO Association to project is weak and depends on participants in the session

    def test_service_query_usergroups_for_site(self):
        """
        This will test query_usergroups_for_site.
        """
        with self._flask_app.app_context():

            all_sites = TeraSite.query.all()
            for site in all_sites:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                usergroups = set(service_access.query_usergroups_for_site(site_id = site.id_site))

                # TODO
                # queried_usergroups = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                #                                         .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                #                                         .join(TeraSite, TeraServiceRole.id_site == TeraSite.id_site) \
                #                                         .filter(TeraSite.id_site == site.id_site) \
                #                                         .filter(TeraServiceRole.id_service == service.id_service) \
                #                                         .with_entities(TeraUserGroup).all()

                # self.assertEqual(len(usergroups), len(queried_usergroups))

    def test_service_query_usergroups_for_project(self):
        """
        This will test query_usergroups_for_project.
        """
        with self._flask_app.app_context():

            all_projects = TeraProject.query.all()
            for project in all_projects:
                service =  TeraService.get_service_by_key('VideoRehabService')
                self.assertIsNotNone(service)
                service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
                usergroups = set(service_access.query_usergroups_for_project(project_id = project.id_project))

                # TODO
                # queried_usergroups = TeraServiceAccess.query.join(TeraUserUserGroup, TeraServiceAccess.id_user_group == TeraUserUserGroup.id_user_group) \
                #                                         .join(TeraServiceRole, TeraServiceAccess.id_service_role == TeraServiceRole.id_service_role) \
                #                                         .join(TeraProject, TeraServiceRole.id_project == TeraProject.id_project) \
                #                                         .filter(TeraProject.id_project == project.id_project) \
                #                                         .filter(TeraServiceRole.id_service == service.id_service) \
                #                                         .with_entities(TeraUserGroup).all()

                # self.assertEqual(len(usergroups), len(queried_usergroups))

    def test_service_get_accessible_tests_invitations_ids(self):
        """
        This will test get_accessible_tests_invitations_ids.
        """
        with self._flask_app.app_context():
            service : TeraService =  TeraService.get_service_by_key('VideoRehabService')
            supp_service : TeraService = TeraService.get_service_by_key('LoggingService')
            self.assertIsNotNone(service)
            self.assertIsNotNone(supp_service)

            # Create a test type with this service
            test_type : TeraTestType = TeraTestType()
            test_type.test_type_name = 'TestType'
            test_type.test_type_key = 'TestType'
            test_type.test_type_description = 'TestType'
            test_type.id_service = service.id_service
            TeraTestType.insert(test_type)


            # Create a session type with this service
            session_type : TeraSessionType = TeraSessionType()
            session_type.session_type_name = 'SessionType'
            session_type.session_type_online = False
            session_type.session_type_config = str()
            session_type.session_type_color = '#000000'
            session_type.session_type_category = TeraSessionType.SessionCategoryEnum.SERVICE.value

            session_type.id_service = service.id_service
            session_type.session_type_secondary_services = [supp_service]

            TeraSessionType.insert(session_type)

            # Create a session with this session type
            session : TeraSession = TeraSession()
            session.id_session_type = session_type.id_session_type
            session.id_creator_service = service.id_service
            session.session_name = 'Session'
            session.session_status = TeraSessionStatus.STATUS_NOTSTARTED.value
            session.session_start_datetime = datetime.now()
            session.session_duration = 0
            session.session_participants = []
            session.session_users = []
            session.session_devices = []

            TeraSession.insert(session)

            # Create an invitation for this test type
            invitation : TeraTestInvitation = TeraTestInvitation()
            invitation.id_test_type = test_type.id_test_type
            invitation.id_session = session.id_session
            invitation.id_user = 1
            invitation.id_project = 1
            invitation.test_invitation_creation_date = datetime.now()
            invitation.test_invitation_expiration_date = datetime.now() + timedelta(days=1)

            TeraTestInvitation.insert(invitation)

            # Service should have access to invitation
            service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(service)
            self.assertTrue(invitation.id_test_invitation in service_access.get_accessible_tests_invitations_ids())

            # Supp service should also have access to invitation
            # service_access : DBManagerTeraServiceAccess = DBManager.serviceAccess(supp_service)
            # self.assertTrue(invitation.id_test_invitation in service_access.get_accessible_tests_invitations_ids())
