import os

import pytest

import fbnconfig
import tests.integration.identity as identity

if os.getenv("FBN_ACCESS_TOKEN") is None or os.getenv("LUSID_ENV") is None:
    raise (
        RuntimeError("Both FBN_ACCESS_TOKEN and LUSID_ENV variables need to be set to run these tests")
    )

lusid_env = os.environ["LUSID_ENV"]
token = os.environ["FBN_ACCESS_TOKEN"]
host_vars = {}


def test_teardown():
    deployment_name = identity.configure(host_vars).id
    fbnconfig.deployex(fbnconfig.Deployment(deployment_name, []), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token)
    matches = get_roles_by_name(client, "robTest_role2")
    assert len(matches) == 0
    users = get_users_by_login(client, "robtest_jane3@robtest.com")
    assert len(users) == 0


@pytest.mark.skip(reason="This creates actual users; should be run explicitly")
def test_create():
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token)
    matches = get_roles_by_name(client, "robTest_role2")
    assert len(matches) == 1
    users = get_users_by_login(client, "robtest_jane3@robtest.com")
    assert len(users) == 1


def test_update():
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token)
    matches = get_roles_by_name(client, "robTest_role2")
    assert len(matches) == 1
    users = get_users_by_login(client, "robtest_jane3@robtest.com")
    assert len(users) == 1


def get_roles_by_name(client, name):
    get = client.request("get", "/identity/api/roles")
    get.raise_for_status()
    roles = get.json()
    return [role for role in roles if role["name"] == name]


def get_users_by_login(client, login):
    get = client.request("get", "/identity/api/users")
    get.raise_for_status()
    users = get.json()
    return [user for user in users if user["login"] == login]


@pytest.mark.asyncio
async def test_role_list():
    # GIVEN Role is deployed
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    code = "robTest_role2"
    # WHEN the fetch method is called for that resource
    response = await identity.identity.IdentityRoleResource.list(
        client=client,
        query_params={},
        path_params={}
    )
    role = [role for role in response["values"] if role["value"]["name"] == code]
    role_id = role[0]["value"]["roleId"]
    # THEN the response is as expected
    expected_role = [{
        "keys": {
            "roleId": role_id
        },
        "value": {
            "id": f"identity-role_{role_id}".lower(),
            "roleId": role_id,
            "code": code,
            "name": code,
            "scope": "default",
            "description": "scheduler-operators"
        }
    }]
    assert role == expected_role


@pytest.mark.asyncio
async def test_role_fetch():
    # GIVEN Role is deployed
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    roles_response = await client.request("get", "/identity/api/roles")
    roles = roles_response.json()
    code = "robTest_role2"
    role_id = [role for role in roles if role["name"] == code][0]["id"]
    # WHEN the fetch method is called for that resource
    response = await identity.identity.IdentityRoleResource.fetch(
        client=client,
        keys={
            "roleId": role_id
        }
    )
    # THEN the response is as expected
    expected_response = {
        "id": f"identity-role_{role_id}".lower(),
        "roleId": role_id,
        "code": code,
        "name": code,
        "scope": "default",
        "description": "scheduler-operators"
    }
    assert response == expected_response


@pytest.mark.asyncio
async def test_role_assignment_list():
    # GIVEN RoleAssignment is deployed
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    roles_response = await client.request("get", "/identity/api/roles")
    roles = roles_response.json()
    role_code = "robTest_role2"
    role_id = [role for role in roles if role["name"] == role_code][0]["id"]
    users_response = await client.request("get", "/identity/api/users")
    users = users_response.json()
    user_login = "robtest_jane3@robtest.com"
    user_id = [user for user in users if user["login"] == user_login][0]["id"]
    # WHEN the fetch method is called for that resource
    response = await identity.identity.RoleAssignment.list(
        client=client,
        query_params={},
        path_params={
            "roleId": role_id,
        }
    )
    # THEN the response is as expected
    expected_role = {
        "values": [
            {
                "keys": {
                    "roleId": role_id,
                    "userId": user_id
                },
                "value": {
                    "id": f"role-assignment_{role_id}_{user_id}".lower(),
                    "roleId": role_id,
                    "userId": user_id,
                    "role": {
                        "$ref": f"identity-role_{role_id}".lower()
                    },
                    "user": {
                        "$ref": f"user_{user_id}".lower()
                    }
                }
            }
        ]
    }
    assert response == expected_role


@pytest.mark.asyncio
async def test_user_list():
    # GIVEN User is deployed
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    login = "robtest_jane3@robtest.com"
    # WHEN the fetch method is called for that resource
    response = await identity.identity.UserResource.list(
        client=client,
        query_params={},
        path_params={}
    )
    user = [user for user in response["values"] if user["value"]["login"] == login]
    user_id = user[0]["keys"]["userId"]
    # THEN the response is as expected
    expected_role = [{
        "keys": {
            "userId": user_id
        },
        "value": {
            "id": f"user_{user_id}".lower(),
            "emailAddress": "robtest_jane@robert.byrnemail.org",
            "login": login,
            "firstName": "robTestJane",
            "lastName": "robTestSmith",
            "type": "Service",
            "secondEmailAddress": None
        }
    }]
    assert user == expected_role


@pytest.mark.asyncio
async def test_user_fetch():
    # GIVEN User is deployed
    fbnconfig.deployex(identity.configure(host_vars), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    users_response = await client.request("get", "/identity/api/users")
    users = users_response.json()
    login = "robtest_jane3@robtest.com"
    user_id = [user for user in users if user["login"] == login][0]["id"]
    # WHEN the fetch method is called for that resource
    response = await identity.identity.UserResource.fetch(
        client=client,
        keys={
            "userId": user_id
        }
    )
    # THEN the response is as expected
    expected_response = {
        "id": f"user_{user_id}".lower(),
        "emailAddress": "robtest_jane@robert.byrnemail.org",
        "login": login,
        "firstName": "robTestJane",
        "lastName": "robTestSmith",
        "type": "Service",
        "secondEmailAddress": None
    }
    assert response == expected_response
