#pylint: disable=invalid-name, missing-function-docstring, line-too-long, logging-fstring-interpolation, missing-class-docstring, missing-module-docstring
import inspect
import os
import json
import requests_mock
import traceback

from ..cm_connection import CmConnection
from ..tf import set_config_for_service

access_token = r'{"access_token":"eyI3...","expires_in":3600,"refresh_expires_in":0,"refresh_token":"ey...","token_type":"Bearer","not-before-policy":0,"session_state":"f6e235c4-4ca4-4258-bede-4f2b7125adfb","scope":"profile email offline_access"}'

resources = os.path.join(os.path.dirname(os.path.abspath(inspect.stack()[0][1])), "resources")
with open(os.path.join(resources, "constellation-by-name-hub1.json"), "r", encoding="UTF-8") as f:
    res_constellation_by_name_hub1 = f.read()
with open(os.path.join(resources, "connections-expanded.json"), "r", encoding="UTF-8") as f:
    j = json.load(f)
    # Fake reference data to have the name this test case needs for the given teraflow UUID
    # (=no need for too large set of reference material)
    j[0]["state"]["name"] = "TF:12345ABCDEFGHIJKLMN"
    res_connection_by_name_json = [j[0]] # Single item list

def mock_cm():
    m = requests_mock.Mocker()
    m.post('https://127.0.0.1:9999/realms/xr-cm/protocol/openid-connect/token', text=access_token)
    m.get("https://127.0.0.1:9999/api/v1/ns/xr-networks?content=expanded&content=expanded&q=%7B%22hubModule.state.module.moduleName%22%3A+%22XR+HUB+1%22%7D", text=res_constellation_by_name_hub1)
    m.post("https://127.0.0.1:9999/api/v1/ncs/network-connections", text='[{"href":"/network-connections/c3b31608-0bb7-4a4f-9f9a-88b24a059432","rt":["cm.network-connection"]}]', status_code=202)
    return m

uuid = "12345ABCDEFGHIJKLMN"
config = {
    "input_sip": "XR HUB 1|XR-T4;",
    "output_sip": "XR LEAF 1|XR-T1",
    "capacity_value": 125,
    "capacity_unit": "gigabit"
}

def _validate_result(result, expect):
    if isinstance(result, Exception):
        traceback.print_exception(result)
    assert result is expect # Not, "is", not ==, we want type checking in this case, as also an exception can be returned (as return value)

def test_xr_set_config():
    with mock_cm() as m:
        cm = CmConnection("127.0.0.1", 9999, "xr-user", "xr-password", tls_verify=False)
        assert cm.Connect()

        constellation = cm.get_constellation_by_hub_name("XR HUB 1")
        assert constellation

        result = set_config_for_service(cm, constellation, uuid, config)
        _validate_result(result, True)

        called_mocks = [(r._request.method, r._request.url) for r in m._adapter.request_history]
        expected_mocks = [
            ('POST', 'https://127.0.0.1:9999/realms/xr-cm/protocol/openid-connect/token'), # Authentication
            ('GET',  'https://127.0.0.1:9999/api/v1/ns/xr-networks?content=expanded&content=expanded&q=%7B%22hubModule.state.module.moduleName%22%3A+%22XR+HUB+1%22%7D'),  # Hub module by name
            ('GET',  'https://127.0.0.1:9999/api/v1/ncs/network-connections?content=expanded&q=%7B%22state.name%22%3A+%22TF%3A12345ABCDEFGHIJKLMN%22%7D'),  # Get by name, determine update or create
            ('POST', 'https://127.0.0.1:9999/api/v1/ncs/network-connections') # Create
        ]
        assert called_mocks == expected_mocks

def test_xr_set_config_update_case():
    with mock_cm() as m:
        cm = CmConnection("127.0.0.1", 9999, "xr-user", "xr-password", tls_verify=False)
        assert cm.Connect()

        constellation = cm.get_constellation_by_hub_name("XR HUB 1")
        assert constellation

        # Fake existing service (--> update path is taken)
        m.get("https://127.0.0.1:9999/api/v1/ncs/network-connections?content=expanded&q=%7B%22state.name%22%3A+%22TF%3A12345ABCDEFGHIJKLMN%22%7D", json=res_connection_by_name_json)
        # Delete endpoint that is no longer necessary
        m.delete("https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints/1d58ba8f-4d51-4213-83e1-97a0e0bdd388", text="", status_code = 202)
        # Update changed endpoint
        m.put("https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints/230516d0-7e38-44b1-b174-1ba7d4454ee6", text="", status_code = 202)
        # Create the newly added endpoint
        m.post("https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints", json=[{"href":"/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoint/somethingplausible","rt":["plausible"]}], status_code=202)
        # Update the connection itself
        m.put("https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03", text="", status_code=202)

        result = set_config_for_service(cm, constellation, uuid, config)
        _validate_result(result, True)

        called_mocks = [(r._request.method, r._request.url) for r in m._adapter.request_history]
        expected_mocks = [
            ('POST',   'https://127.0.0.1:9999/realms/xr-cm/protocol/openid-connect/token'), # Authentication
            ('GET',    'https://127.0.0.1:9999/api/v1/ns/xr-networks?content=expanded&content=expanded&q=%7B%22hubModule.state.module.moduleName%22%3A+%22XR+HUB+1%22%7D'),  # Hub module by name
            ('GET',    'https://127.0.0.1:9999/api/v1/ncs/network-connections?content=expanded&q=%7B%22state.name%22%3A+%22TF%3A12345ABCDEFGHIJKLMN%22%7D'),  # Get by name, determine update or create
            ('DELETE', 'https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints/1d58ba8f-4d51-4213-83e1-97a0e0bdd388'), # Delete unnecessary endpoint
            ('PUT',    'https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints/230516d0-7e38-44b1-b174-1ba7d4454ee6'), # Update changed endpoint
            ('POST',   'https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03/endpoints'), # Add new endpoint
            ('PUT',    'https://127.0.0.1:9999/api/v1/ncs/network-connections/4505d5d3-b2f3-40b8-8ec2-4a5b28523c03') # Update the connection itself
        ]
        assert called_mocks == expected_mocks
