# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging, operator
from common.proto.context_pb2 import Connection, Service
from common.proto.pathcomp_pb2 import PathCompReply
from common.tools.grpc.Tools import grpc_message_to_json_string
from service.service.DependencyResolver import resolve_dependencies

LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)

def test_dependency_resolver():
    # test: add services and connections that depend on each other
    #       then, check if they are properly resolved.
    # - service MAIN, depends on connection PKT-1, TAPI, and PKT-2
    # - connection PKT-1, depends on nothing
    # - connection TAPI, depends on service TAPI-1 and TAPI-2
    # - connection PKT-2, depends on nothing
    # - service TAPI-1, depends on connection TAPI-1
    # - service TAPI-2, depends on connection TAPI-2

    pathcomp_reply = PathCompReply()

    service_main = pathcomp_reply.services.add()
    service_main.service_id.context_id.context_uuid.uuid = 'admin'
    service_main.service_id.service_uuid.uuid = 'MAIN'

    service_tapi1 = pathcomp_reply.services.add()
    service_tapi1.service_id.context_id.context_uuid.uuid = 'admin'
    service_tapi1.service_id.service_uuid.uuid = 'TAPI-1'

    service_tapi2 = pathcomp_reply.services.add()
    service_tapi2.service_id.context_id.context_uuid.uuid = 'admin'
    service_tapi2.service_id.service_uuid.uuid = 'TAPI-2'

    connection_pkt1 = pathcomp_reply.connections.add()
    connection_pkt1.connection_id.connection_uuid.uuid = 'PKT-1'
    connection_pkt1.service_id.CopyFrom(service_main.service_id)

    connection_tapi = pathcomp_reply.connections.add()
    connection_tapi.connection_id.connection_uuid.uuid = 'TAPI'
    connection_tapi.service_id.CopyFrom(service_main.service_id)

    connection_pkt2 = pathcomp_reply.connections.add()
    connection_pkt2.connection_id.connection_uuid.uuid = 'PKT-2'
    connection_pkt2.service_id.CopyFrom(service_main.service_id)

    connection_tapi1 = pathcomp_reply.connections.add()
    connection_tapi1.connection_id.connection_uuid.uuid = 'TAPI-1'
    connection_tapi1.service_id.CopyFrom(service_tapi1.service_id)
    connection_tapi.sub_service_ids.append(service_tapi1.service_id)

    connection_tapi2 = pathcomp_reply.connections.add()
    connection_tapi2.connection_id.connection_uuid.uuid = 'TAPI-2'
    connection_tapi2.service_id.CopyFrom(service_tapi2.service_id)
    connection_tapi.sub_service_ids.append(service_tapi2.service_id)

    LOGGER.info('pathcomp_reply={:s}'.format(grpc_message_to_json_string(pathcomp_reply)))
    resolution = resolve_dependencies(pathcomp_reply)
    LOGGER.info('resolution={:s}'.format(str(list(map(operator.itemgetter(0), resolution)))))

    CORRECT_RESOLUTION_KEYS = [
        ('connection', 'PKT-1'       ),
        ('connection', 'PKT-2'       ),
        ('connection', 'TAPI-1'      ),
        ('connection', 'TAPI-2'      ),
        ('service'   , 'admin/TAPI-1'),
        ('service'   , 'admin/TAPI-2'),
        ('connection', 'TAPI'        ),
        ('service'   , 'admin/MAIN'  ),
    ]
    for (resolved_key,(resolved_objid, resolved_obj)),correct_key in zip(resolution, CORRECT_RESOLUTION_KEYS):
        assert resolved_key == correct_key
        assert resolved_obj is not None
        if resolved_key[0] == 'connection':
            assert isinstance(resolved_obj, Connection)
            assert resolved_objid == resolved_obj.connection_id
            connection_key = resolved_obj.connection_id.connection_uuid.uuid
            assert resolved_key[1] == connection_key
        elif resolved_key[0] == 'service':
            assert isinstance(resolved_obj, Service)
            assert resolved_objid == resolved_obj.service_id
            context_uuid = resolved_obj.service_id.context_id.context_uuid.uuid
            service_uuid = resolved_obj.service_id.service_uuid.uuid
            service_key = '/'.join([context_uuid, service_uuid])
            assert resolved_key[1] == service_key
