#!/usr/bin/env python3
#pylint: disable=invalid-name, missing-function-docstring, line-too-long, logging-fstring-interpolation, missing-class-docstring, missing-module-docstring
# 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.

# Manage L2 services (with underlying XR connectivity) without need to use unit test
# files or excessive JSON definitions
#
# Run in this directory with PYTHONPATH=../../../../
# E.g.:
#     PYTHONPATH=../../../../  ./service-cli.py create 1 R1-EMU 13/1/2 500 2 R3-EMU 13/1/2 500
#     PYTHONPATH=../../../../  ./service-cli.py list
#     PYTHONPATH=../../../../  ./service-cli.py delete 43a8046a-5dec-463d-82f7-7cc3442dbf4f


import argparse
import logging
import traceback
from contextlib import contextmanager

from common.Settings import get_setting
from context.client.ContextClient import ContextClient
from tests.tools.mock_osm.MockOSM import MockOSM
from common.proto.context_pb2 import ContextId, ServiceTypeEnum, ServiceStatusEnum
from common.tools.grpc.Tools import grpc_message_to_json_string

LOGGER = logging.getLogger(__name__)

WIM_USERNAME = 'admin'
WIM_PASSWORD = 'admin'

@contextmanager
def make_context_client():
    try:
        _client = ContextClient(get_setting('CONTEXTSERVICE_SERVICE_HOST'), get_setting('CONTEXTSERVICE_SERVICE_PORT_GRPC'))
        yield _client
    finally:
        _client.close()

def make_osm_wim():
    wim_url = 'http://{:s}:{:s}'.format(
        get_setting('COMPUTESERVICE_SERVICE_HOST'), str(get_setting('COMPUTESERVICE_SERVICE_PORT_HTTP')))
    return MockOSM(wim_url, WIM_MAPPING, WIM_USERNAME, WIM_PASSWORD)

logging.basicConfig(level=logging.ERROR)

parser = argparse.ArgumentParser(description='TF Service Management Utility')
subparsers = parser.add_subparsers(dest="command")
subparsers.required = True

create_parser = subparsers.add_parser('create')
create_parser.add_argument('site1', type=int, help='One endpoint of the service, e.g. 1')
create_parser.add_argument('device1', type=str, help='One endpoint of the service, e.g. R1-EMU')
create_parser.add_argument('interface1', type=str, help='One endpoint of the service, e.g. 13/1/2')
create_parser.add_argument('vlan1', type=int, help='VLAN in first endpoint, e.g. 500')

create_parser.add_argument('site2', type=int, help='One endpoint of the service, e.g. 2')
create_parser.add_argument('device2', type=str, help='One endpoint of the service, e.g. R3-EMU')
create_parser.add_argument('interface2', type=str, help='One endpoint of the service, e.g. 13/1/2')
create_parser.add_argument('vlan2', type=int, help='VLAN in first endpoint, e.g. 500')

delete_parser = subparsers.add_parser('delete')
delete_parser.add_argument('service_uuid', type=str, help='UUID of the service to be deleted')

list_parser = subparsers.add_parser('list')

args = parser.parse_args()

WIM_SERVICE_TYPE = 'ELINE'
CONTEXT_ID = {'context_uuid': {'uuid': 'admin'}}

if args.command == "create":
    endpoint1 = f"{args.device1}:{args.interface1}"
    endpoint2 = f"{args.device2}:{args.interface2}"

    WIM_MAPPING  = [
        {'device-id': args.device1, 'service_endpoint_id': endpoint1,
        'service_mapping_info': {'bearer': {'bearer-reference': endpoint1}, 'site-id': args.site1}},
        {'device-id': args.device2, 'service_endpoint_id': endpoint2,
        'service_mapping_info': {'bearer': {'bearer-reference': endpoint2}, 'site-id': args.site2}},
    ]
    WIM_SERVICE_CONNECTION_POINTS = [
        {'service_endpoint_id': endpoint1,
            'service_endpoint_encapsulation_type': 'dot1q',
            'service_endpoint_encapsulation_info': {'vlan': args.vlan1}},
        {'service_endpoint_id': endpoint2,
            'service_endpoint_encapsulation_type': 'dot1q',
            'service_endpoint_encapsulation_info': {'vlan': args.vlan2}},
    ]
else:
    WIM_MAPPING = []
    WIM_SERVICE_CONNECTION_POINTS = []

#print(str(args))
print(f"=== WIM_SERVICE_TYPE: {WIM_SERVICE_TYPE}")
print(f"=== WIM_SERVICE_CONNECTION_POINTS: {WIM_SERVICE_CONNECTION_POINTS}")
print(f"=== WIM_MAPPING: {WIM_MAPPING}")

with make_context_client() as client:
    osm_wim = make_osm_wim();

    if args.command == "create":
        service_uuid = osm_wim.create_connectivity_service(WIM_SERVICE_TYPE, WIM_SERVICE_CONNECTION_POINTS)
        print(f"*** Create connectivity service --> {service_uuid}")
        status = osm_wim.get_connectivity_service_status(service_uuid)
        print(f"*** Get created service status --> {str(status)}")

    elif args.command == "delete":
        osm_wim.wim.check_credentials()
        try:
            osm_wim.wim.delete_connectivity_service(args.service_uuid)
            print(f"*** Service {args.service_uuid} is no longer present (delete was successfull or service did not exist)")
        except Exception as e:
            print(f"*** Failed to delete service {args.service_uuid}, {e}")
    elif args.command == "list":
        response = client.ListServices(ContextId(**CONTEXT_ID))

        #print('Services[{:d}] = {:s}'.format(len(response.services), grpc_message_to_json_string(response)))
        for service in response.services:
            scs = ""
            
            # See if there are endpoint constraints that might be regognizable by the user.
            # Keys do not necessarily exist, so catch exceptions and ignore those constraints
            # that we cannot easily represent.
            for sc in service.service_constraints:
                try:
                    scs += f"{sc.endpoint_location.endpoint_id.device_id.device_uuid.uuid}:{sc.endpoint_location.endpoint_id.endpoint_uuid.uuid} "
                except Exception:
                    pass

            print(f"{service.service_id.service_uuid.uuid:36}  {ServiceTypeEnum.Name(service.service_type):40}  {ServiceStatusEnum.Name(service.service_status.service_status)}  {scs}")


