import os
from types import SimpleNamespace

import pytest
from pytest import fixture

import fbnconfig
import tests.integration.sequence as sequence
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(scope="module")
def setup_deployment():
    deployment_name = gen("sequence")
    print(f"\nRunning for deployment {deployment_name}...")
    yield SimpleNamespace(name=deployment_name)
    # Cant tear down sequence resources as no api to delete


def test_create(setup_deployment):
    fbnconfig.deployex(sequence.configure(setup_deployment), lusid_env, token)
    client.get(f"/api/api/sequences/{setup_deployment.name}/seq1").json()


def test_nochange(setup_deployment):
    fbnconfig.deployex(sequence.configure(setup_deployment), lusid_env, token)
    update = fbnconfig.deployex(sequence.configure(setup_deployment), lusid_env, token)
    assert [a.change for a in update if a.type == "SequenceResource"] == ["nochange"]


@pytest.mark.asyncio
async def test_sequence_list_with_filter(setup_deployment):
    # GIVEN Sequence is deployed
    fbnconfig.deployex(sequence.configure(setup_deployment), lusid_env, token)
    scope = setup_deployment.name
    code = "seq1"
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    # WHEN calling list with filter for the deployment name
    result = await sequence.sequence.SequenceResource.list(
        client=client,
        query_params={"filter": f"id.code eq '{code}' and id.scope eq '{scope}'"},
        path_params={}
    )
    # THEN the result has correct structure
    expected_result = {
        "values": [
            {
                "keys": {
                    "code": code,
                    "scope": scope
                },
                "value": {
                    "id": f"sequence_{scope}_{code}".lower(),
                    "code": code,
                    "scope": scope,
                    "cycle": False,
                    "increment": 1,
                    "start": 1,
                    "minValue": 1,
                    "maxValue": 9223372036854775807,
                }
            }
        ]
    }
    assert result == expected_result


@pytest.mark.asyncio
async def test_sequence_fetch(setup_deployment):
    # GIVEN Sequence is deployed
    fbnconfig.deployex(sequence.configure(setup_deployment), lusid_env, token)
    scope = setup_deployment.name
    code = "seq1"
    client = fbnconfig.create_client(lusid_env, token, is_async=True)
    # WHEN the fetch method is called for that resource
    response = await sequence.sequence.SequenceResource.fetch(
        client=client,
        keys={
            "code": code,
            "scope": scope
        }
    )
    # THEN the response is as expected
    expected_response = {
        "id": f"sequence_{scope}_{code}".lower(),
        "code": code,
        "scope": scope,
        "cycle": False,
        "increment": 1,
        "start": 1,
        "minValue": 1,
        "maxValue": 9223372036854775807,
    }
    assert response == expected_response
