# Copyright 2022-2023 ETSI TeraFlowSDN - TFS OSG (https://tfs.etsi.org/)
#
# 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, os, grpc
from common.method_wrappers.Decorator import MetricsPool, safe_and_metered_rpc_method
from common.proto.context_pb2 import Empty

from common.Constants import ServiceNameEnum
from common.Settings import get_service_port_grpc
from common.proto.kpi_manager_pb2_grpc import add_KpiManagerServiceServicer_to_server
from common.proto.kpi_manager_pb2_grpc import KpiManagerServiceServicer
from monitoring.service.NameMapping import NameMapping

from common.proto.kpi_manager_pb2 import kpiDescriptor, KpiId, KpiDescriptorList
from monitoring.service import ManagementDBTools

from common.tools.service.GenericGrpcService import GenericGrpcService

LOGGER = logging.getLogger(__name__)

METRICS_POOL = MetricsPool('Monitoring', 'RPC')

class KpiManagerServer(KpiManagerServiceServicer):
    def __init__(self, cls_name: str = __name__):
        LOGGER.info('Init KpiManagerService')
        port = get_service_port_grpc(ServiceNameEnum.KPIMANAGER) # port updated
        GenericGrpcService(port, cls_name = cls_name) # class inheretence was removed

        # Init sqlite monitoring db
        self.management_db = ManagementDBTools.ManagementDB('monitoring.db') # why monitoring.db here???
        LOGGER.info('MetricsDB initialized --- KPI Manager Service')

    def install_servicers(self):
        # There is no need to create the "MonitoringServiceServicerImpl" instance because actual class
        # implementation exists in the same class. 
        add_KpiManagerServiceServicer_to_server(KpiManagerServer(), self.server)
    
    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def SetKpi(
            self, request: KpiDescriptor, grpc_context: grpc.ServicerContext
    ) -> KpiId:
        response = KpiId()
        kpi_description = request.kpi_description
        kpi_sample_type = request.kpi_sample_type
        kpi_device_id = request.device_id.device_uuid.uuid
        kpi_endpoint_id = request.endpoint_id.endpoint_uuid.uuid
        kpi_service_id = request.service_id.service_uuid.uuid
        kpi_slice_id = request.slice_id.slice_uuid.uuid
        kpi_connection_id = request.connection_id.connection_uuid.uuid
        kpi_link_id = request.link_id.link_uuid.uuid
        if request.kpi_id.kpi_id.uuid != "":
            response.kpi_id.uuid = request.kpi_id.kpi_id.uuid
            # Here the code to modify an existing kpi
        else:
            data = self.management_db.insert_KPI(
                kpi_description, kpi_sample_type, kpi_device_id, kpi_endpoint_id, 
                kpi_service_id, kpi_slice_id, kpi_connection_id, kpi_link_id)
            response.kpi_id.uuid = str(data)
        return response

    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def DeleteKpi(self, request: KpiId, grpc_context: grpc.ServicerContext) -> Empty:
        kpi_id = int(request.kpi_id.uuid)
        kpi = self.management_db.get_KPI(kpi_id)
        if kpi:
            self.management_db.delete_KPI(kpi_id)
        else:
            LOGGER.info('DeleteKpi error: KpiID({:s}): not found in database'.format(str(kpi_id)))
        return Empty()

    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def GetKpiDescriptor(self, request: KpiId, grpc_context: grpc.ServicerContext) -> KpiDescriptor:
        kpi_id = request.kpi_id.uuid
        kpi_db = self.management_db.get_KPI(int(kpi_id))
        kpiDescriptor = KpiDescriptor()
        if kpi_db is None:
            LOGGER.info('GetKpiDescriptor error: KpiID({:s}): not found in database'.format(str(kpi_id)))
        else:
            kpiDescriptor.kpi_description                       = kpi_db[1]
            kpiDescriptor.kpi_sample_type                       = kpi_db[2]
            kpiDescriptor.device_id.device_uuid.uuid            = str(kpi_db[3])
            kpiDescriptor.endpoint_id.endpoint_uuid.uuid        = str(kpi_db[4])
            kpiDescriptor.service_id.service_uuid.uuid          = str(kpi_db[5])
            kpiDescriptor.slice_id.slice_uuid.uuid              = str(kpi_db[6])
            kpiDescriptor.connection_id.connection_uuid.uuid    = str(kpi_db[7])
            kpiDescriptor.link_id.link_uuid.uuid                = str(kpi_db[8])
        return kpiDescriptor

    @safe_and_metered_rpc_method(METRICS_POOL, LOGGER)
    def GetKpiDescriptorList(self, request: Empty, grpc_context: grpc.ServicerContext) -> KpiDescriptorList:
        kpi_descriptor_list = KpiDescriptorList()
        data = self.management_db.get_KPIS()
        LOGGER.debug(f"data: {data}")
        for item in data:
            kpi_descriptor = KpiDescriptor()
            kpi_descriptor.kpi_id.kpi_id.uuid                   = str(item[0])
            kpi_descriptor.kpi_description                      = item[1]
            kpi_descriptor.kpi_sample_type                      = item[2]
            kpi_descriptor.device_id.device_uuid.uuid           = str(item[3])
            kpi_descriptor.endpoint_id.endpoint_uuid.uuid       = str(item[4])
            kpi_descriptor.service_id.service_uuid.uuid         = str(item[5])
            kpi_descriptor.slice_id.slice_uuid.uuid             = str(item[6])
            kpi_descriptor.connection_id.connection_uuid.uuid   = str(item[7])
            kpi_descriptor.link_id.link_uuid.uuid               = str(item[8])
            kpi_descriptor_list.kpi_descriptor_list.append(kpi_descriptor)
        return kpi_descriptor_list