import os
from types import SimpleNamespace

import pytest
from httpx import HTTPStatusError
from pytest import fixture

import fbnconfig
import tests.integration.datatype as example
from fbnconfig import datatype
from tests.integration.generate_test_name import gen

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 = {}
client = fbnconfig.create_client(lusid_env, token)


@fixture
def setup_deployment():
    deployment_name = gen("datatype")
    print(f"\nRunning for deployment {deployment_name}...")
    yield SimpleNamespace(name=deployment_name)
    print("\nTearing down resources...")
    fbnconfig.deployex(fbnconfig.Deployment(deployment_name, []), lusid_env, token)


def test_teardown(setup_deployment):
    fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)

    fbnconfig.deployex(fbnconfig.Deployment(setup_deployment.name, []), lusid_env, token)
    client = fbnconfig.create_client(lusid_env, token)
    try:
        client.get(f"/api/api/datatypes/{setup_deployment.name}/robtest_strategy")
    except HTTPStatusError as error:
        # check it was deleted
        assert error.response.status_code == 404


def test_create(setup_deployment):
    fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)
    res = client.get(f"/api/api/datatypes/{setup_deployment.name}/robtest_priority").json()
    assert res is not None


def test_nochange(setup_deployment):
    fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)
    update = fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)
    print(update)
    assert [a.change for a in update] == ["nochange"] * 3


@pytest.mark.asyncio
async def test_list(setup_deployment):
    # GIVEN DataType is deployed
    fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)
    scope = setup_deployment.name
    code = "robtest_priority"
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    # WHEN calling list with filter for that code
    result = await datatype.DataTypeResource.list(
        client=client,
        query_params={
            "filter": f"id.code eq '{code}' and id.scope eq '{scope}'"
        }
    )
    # THEN the result matches expected structure
    expected_result = {
        "values": [
            {
                "keys": {
                    "code": code,
                    "scope": scope,
                },
                "value": {
                    "id": f"datatype_{scope}_{code}".lower(),
                    "scope": scope,
                    "code": code,
                    "acceptableUnits": [],
                    "acceptableValues": [
                        "High",
                        "Low",
                        "Medium",
                    ],
                    "description": "A test datatype for Priority",
                    "displayName": "Priority Test",
                    "typeValueRange": "Closed",
                    "unitSchema": "NoUnits",
                    "valueType": "String",
                }
            }
        ]
    }
    assert result == expected_result


@pytest.mark.asyncio
async def test_fetch(setup_deployment):
    # GIVEN DataType is deployed
    fbnconfig.deployex(example.configure(setup_deployment), lusid_env, token)
    scope = setup_deployment.name
    code = "robtest_priority"
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    # WHEN the fetch method is called for that resource
    response = await datatype.DataTypeResource.fetch(
        client=client,
        keys={
            "scope": scope,
            "code": code
        }
    )
    # THEN the response is as expected
    expected_response = {
        "id": f"datatype_{scope}_{code}".lower(),
        "scope": scope,
        "code": code,
        "acceptableUnits": [],
        "acceptableValues": [
            "High",
            "Low",
            "Medium"
        ],
        "description": "A test datatype for Priority",
        "displayName": "Priority Test",
        "valueType": "String",
        "typeValueRange": "Closed",
        "unitSchema": "NoUnits",
        "referenceData": {
            "fieldDefinitions": [],
            "values": []
        },
    }
    assert response == expected_response
