# Copyright (c) 2022 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com


from uuid import uuid4

import pytest

from czc.api.environment import TestKeyEnvironment
from czc.function_simulation import MATCHES_ANY, SimulationParameters
from czt.unittest import Context

from tests.sample_data import sample_functions


@pytest.fixture(scope='function')
def context(mocker, mock_lambda_client, mock_table):
    import czc.function_simulation as function_simulation

    with Context(
        mocker, function_simulation, [], {'function_simulation': function_simulation, 'test_key': str(uuid4())}
    ) as context:
        yield context


MAPPING_DATA = {'field1': 'value1', 'field2': 'value2'}

DATA_TYPE_TESTS = [
    pytest.param(None, id='none'),
    pytest.param(10, id='int'),
    pytest.param('Some-string', id='string'),
    pytest.param(True, id='bool'),
    pytest.param(['1', '2', '3'], id='list'),
    pytest.param(MAPPING_DATA, id='mapping'),
]


@pytest.mark.unit
@pytest.mark.parametrize('response', DATA_TYPE_TESTS)
def test_simulated_function_with_different_response_types(context, response):
    sample_functions.function_with_no_args(
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=response)
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_no_args() == response


@pytest.mark.unit
def test_simulated_function_without_test_key(context):
    sample_functions.function_with_no_args(
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA)
    )
    assert sample_functions.function_with_no_args() == sample_functions.function_with_no_args.__name__


@pytest.mark.unit
def test_simulated_function_with_test_key_but_no_simulated_response(context):
    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_no_args() == sample_functions.function_with_no_args.__name__


@pytest.mark.unit
def test_simulated_function_with_args_returns_responses_based_on_args(context):
    sample_functions.function_with_args(
        'value1', 'value2', 'value3', __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA)
    )
    sample_functions.function_with_args(
        'value1', 'value2', __set_simulation__=SimulationParameters(test_key=context.test_key, response='Test')
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args('value1', 'value2') == 'Test'
        assert sample_functions.function_with_args('value1', 'value2', 'value3') == MAPPING_DATA
        assert sample_functions.function_with_args('value1', 'value2', 'different_value').startswith(
            sample_functions.function_with_args.__name__
        )
        assert sample_functions.function_with_args('value1', 'different-value2').startswith(
            sample_functions.function_with_args.__name__
        )


@pytest.mark.unit
def test_simulated_function_with_named_args_returns_responses_based_on_args(context):
    sample_functions.function_with_args_named_args(
        'value1',
        'value2',
        arg3='value3',
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA),
    )
    sample_functions.function_with_args_named_args(
        'value1', 'value2', __set_simulation__=SimulationParameters(test_key=context.test_key, response='Test')
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_named_args('value1', 'value2') == 'Test'
        assert sample_functions.function_with_args_named_args('value1', 'value2', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_named_args('value1', 'value2', arg3='different_value').startswith(
            sample_functions.function_with_args_named_args.__name__
        )
        assert sample_functions.function_with_args_named_args('value1', 'different-value2').startswith(
            sample_functions.function_with_args_named_args.__name__
        )


@pytest.mark.unit
def test_simulated_function_with_args_list_returns_responses_based_on_args(context):
    sample_functions.function_with_args_list(
        'value1', 'value2', 'value3', __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA)
    )
    sample_functions.function_with_args_list(
        'value1', 'value2', __set_simulation__=SimulationParameters(test_key=context.test_key, response='Test')
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_list('value1', 'value2') == 'Test'
        assert sample_functions.function_with_args_list('value1', 'value2', 'value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list('value1', 'value2', 'different_value').startswith(
            sample_functions.function_with_args_list.__name__
        )
        assert sample_functions.function_with_args_list('value1', 'different-value2').startswith(
            sample_functions.function_with_args_list.__name__
        )


@pytest.mark.unit
def test_simulated_function_with_kwargs_returns_responses_based_on_args(context):
    sample_functions.function_with_kwargs(
        arg1='value1',
        arg2='value2',
        arg3='value3',
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA),
    )
    sample_functions.function_with_kwargs(
        arg1='value1', arg2='value2', __set_simulation__=SimulationParameters(test_key=context.test_key, response='Test')
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_kwargs(arg1='value1', arg2='value2') == 'Test'
        assert sample_functions.function_with_kwargs(arg1='value1', arg2='value2', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_kwargs(arg1='value1', arg2='value2', arg3='different_value').startswith(
            sample_functions.function_with_kwargs.__name__
        )
        assert sample_functions.function_with_kwargs(arg1='value1', arg2='different-value2').startswith(
            sample_functions.function_with_kwargs.__name__
        )


@pytest.mark.unit
def test_simulated_function_with_args_list_and_kwargs_returns_responses_based_on_args(context):
    sample_functions.function_with_args_list_and_kwargs(
        'value1',
        arg2='value2',
        arg3='value3',
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA),
    )
    sample_functions.function_with_args_list_and_kwargs(
        'value1', arg2='value2', __set_simulation__=SimulationParameters(test_key=context.test_key, response='Test')
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='value2') == 'Test'
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='value2', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='value2', arg3='different_value').startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='different-value2').startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )


@pytest.mark.unit
@pytest.mark.parametrize('arg1', DATA_TYPE_TESTS)
@pytest.mark.parametrize('arg2', DATA_TYPE_TESTS)
def test_simulated_function_with_different_arg_types(context, arg1, arg2):
    sample_functions.function_with_args_list_and_kwargs(
        arg1, arg2=arg2, __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA)
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_list_and_kwargs(arg1, arg2=arg2) == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs(arg1, arg2=arg2, arg3='something-different').startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )
        assert sample_functions.function_with_args_list_and_kwargs(arg1, 'something-different', arg2=arg2).startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )


@pytest.mark.unit
def test_simulated_function_matches_any_args(context):
    sample_functions.function_with_args_list_and_kwargs(
        'value1',
        MATCHES_ANY,
        arg3='value3',
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA),
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_list_and_kwargs('value1', 'anything_1', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs('value1', 'anything_2', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs('different-value1', 'anything_1', arg3='value3').startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )
        assert sample_functions.function_with_args_list_and_kwargs('value1', 'anything_1', arg3='different-value3').startswith(
            sample_functions.function_with_args_list_and_kwargs.__name__
        )


@pytest.mark.unit
def test_simulated_function_matches_any_kwargs(context):
    sample_functions.function_with_args_list_and_kwargs(
        'value1',
        arg2=MATCHES_ANY,
        arg3='value3',
        __set_simulation__=SimulationParameters(test_key=context.test_key, response=MAPPING_DATA),
    )

    with TestKeyEnvironment(context.test_key):
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='anything_1', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs('value1', arg2='anything_2', arg3='value3') == MAPPING_DATA
        assert sample_functions.function_with_args_list_and_kwargs(
            'different-value1', arg2='anything_1', arg3='value3'
        ).startswith(sample_functions.function_with_args_list_and_kwargs.__name__)
        assert sample_functions.function_with_args_list_and_kwargs(
            'value1', arg2='anything_1', arg3='different-value3'
        ).startswith(sample_functions.function_with_args_list_and_kwargs.__name__)
