import pytest
from Tanium_v2 import Client, get_question_result, get_action_result
import json


def get_fetch_data():
    with open('test_data/action_results.json', 'r') as f:
        return json.loads(f.read())


BASE_URL = 'https://test.com/'

parse_question_res = {
    'data': [
        {
            'from_canonical_text': 0,
            'group': {
                'and_flag': True,
                'deleted_flag': True,
                'filters': [
                    {
                        'all_times_flag': False,
                        'all_values_flag': False,
                        'delimiter': '',
                        'delimiter_index': 0,
                        'ignore_case_flag': True,
                        'max_age_seconds': 0,
                        'not_flag': False,
                        'operator': 'RegexMatch',
                        'sensor': {
                            'hash': 3409330187,
                            'id': 3,
                            'name': 'Computer Name'
                        },
                        'substring_flag': False,
                        'substring_length': 0,
                        'substring_start': 0,
                        'utf8_flag': False,
                        'value': '.*equals.*',
                        'value_type': 'String'
                    }
                ],
                'not_flag': False,
                'sub_groups': []
            },
            'question_text': 'Get Computer Name from all machines with Computer Name contains \"equals\"',
            'selects': [
                {
                    'sensor': {
                        'hash': 3409330187,
                        'name': 'Computer Name'
                    }
                }
            ],
            'sensor_references': [
                {
                    'name': 'Computer Name',
                    'real_ms_avg': 0,
                    'start_char': '4'
                },
                {
                    'name': 'Computer Name',
                    'real_ms_avg': 0,
                    'start_char': '41'
                }
            ]
        }
    ]
}

parse_question_Folder_Contents_res = {
    "data": [
        {
            "from_canonical_text": 0,
            "question_text": "Get Folder-Contents from all machines",
            "selects": [
                {
                    "sensor": {
                        "hash": 3881863289,
                        "name": "Folder-Contents"
                    }
                }
            ],
            "sensor_references": [
                {
                    "name": "Folder-Contents",
                    "real_ms_avg": 53,
                    "start_char": "4"
                }
            ]
        },
        {
            "from_canonical_text": 0,
            "question_text": "Get Tanium File Contents from all machines",
            "selects": [
                {
                    "sensor": {
                        "hash": 4070262781,
                        "name": "Tanium File Contents"
                    }
                }
            ],
            "sensor_references": [
                {
                    "name": "Folder-Contents",
                    "real_ms_avg": 53,
                    "start_char": "4"
                }
            ]
        }
    ]
}

sensor_res = {
    "data": {
        "parameter_definition": "{\"parameters\":[{\"key\":\"folderPath\"}]}"}
}

CREATE_ACTION_BY_TARGET_GROUP_RES = {
    'package_spec': {'source_id': 12345},
    'name': 'action-name via Demisto API',
    'target_group': {'name': 'target-group-name'},
    'action_group': {'id': 1},
    'expire_seconds': 360}

CREATE_ACTION_BY_HOST_RES = {
    'package_spec':
        {'source_id': 20},
    'name': 'action-name via Demisto API',
    'target_group': {
        'and_flag': True,
        'deleted_flag': True,
        'filters': [
            {'all_times_flag': False,
             'all_values_flag': False,
             'delimiter': '',
             'delimiter_index': 0,
             'ignore_case_flag': True,
             'max_age_seconds': 0,
             'not_flag': False,
             'operator': 'RegexMatch',
             'sensor': {
                 'hash': 3409330187,
                 'id': 3,
                 'name': 'Computer Name'},
             'substring_flag': False,
             'substring_length': 0,
             'substring_start': 0,
             'utf8_flag': False,
             'value': '.*equals.*',
             'value_type': 'String'}],
        'not_flag': False,
        'sub_groups': []},
    'action_group': {
        'id': 1},
    'expire_seconds': 360}

CREATE_ACTION_WITH_PARAMETERS_RES = {
    'package_spec':
        {'source_id': 12345,
         'parameters': [{
             'key': '$1',
             'value': 'true'
         }, {
             'key': '$2',
             'value': 'value'
         }, {
             'key': '$3',
             'value': 'otherValue'}]},
    'name': 'action-name via Demisto API',
    'target_group': {
        'name': 'target-group-name'},
    'action_group': {
        'id': 1},
    'expire_seconds': 360}

QUESTION_RESULTS_RAW = {
    "data": {
        "result_sets": [
            {
                "age": 0,
                "archived_question_id": 0,
                "cache_id": "3891494157",
                "columns": [
                    {
                        "hash": 3409330187,
                        "name": "Computer Name",
                        "type": 1
                    },
                    {
                        "hash": 2801942354,
                        "name": "IPv4 Address",
                        "type": 5
                    },
                    {
                        "hash": 1092986182,
                        "name": "Logged In Users",
                        "type": 1
                    },
                    {
                        "hash": 0,
                        "name": "Count",
                        "type": 3
                    }
                ],
                "estimated_total": 2,
                "mr_tested": 2,
                "rows": [
                    {
                        "cid": 2232836718,
                        "data": [
                            [
                                {
                                    "text": "host-name"
                                }
                            ],
                            [
                                {
                                    "text": "127.0.0.1"
                                }
                            ],
                            [
                                {
                                    "text": "[no results]"
                                }
                            ],
                            [
                                {
                                    "text": "1"
                                }
                            ]
                        ],
                        "id": 699534294
                    }
                ]
            }
        ]
    }
}


QUESTION_RESULTS = [{"ComputerName": "host-name", "IPv4Address": "127.0.0.1", "Count": "1"}]


def test_create_action_body_by_target_group_name(requests_mock):
    client = Client(BASE_URL, 'username', 'password', 'domain')

    requests_mock.post(BASE_URL + 'session/login', json={'data': {'session': 'SESSION-ID'}})
    requests_mock.get(BASE_URL + 'packages/by-name/package-name', json={'data': {'id': 12345, 'expire_seconds': 360}})

    body = client.build_create_action_body(False, 'action-name', '', package_name='package-name',
                                           action_group_id=1, target_group_name='target-group-name')

    body = json.dumps(body)
    res = json.dumps(CREATE_ACTION_BY_TARGET_GROUP_RES)

    assert res == body


def test_create_action_body_by_host(requests_mock):
    client = Client(BASE_URL, 'username', 'password', 'domain')

    requests_mock.post(BASE_URL + 'session/login', json={'data': {'session': 'session-id'}})
    requests_mock.get(BASE_URL + 'packages/20', json={'data': {'id': 12345, 'expire_seconds': 360}})
    requests_mock.post(BASE_URL + 'parse_question', json=parse_question_res)

    body = client.build_create_action_body(True, 'action-name', '', package_id=20, action_group_id=1, hostname='host')

    body = json.dumps(body)
    res = json.dumps(CREATE_ACTION_BY_HOST_RES)

    assert res == body


def test_create_action_body_with_parameters(requests_mock):
    client = Client(BASE_URL, 'username', 'password', 'domain')

    requests_mock.post(BASE_URL + 'session/login', json={'data': {'session': 'session-id'}})
    requests_mock.get(BASE_URL + 'packages/by-name/package-name', json={'data': {'id': 12345, 'expire_seconds': 360}})

    body = client.build_create_action_body(False, 'action-name', '$1=true;$2=value;$3=otherValue',
                                           package_name='package-name', action_group_id=1,
                                           target_group_name='target-group-name')

    body = json.dumps(body)
    res = json.dumps(CREATE_ACTION_WITH_PARAMETERS_RES)

    assert res == body


def test_parse_question_results():
    client = Client(BASE_URL, 'username', 'password', 'domain')
    results = client.parse_question_results(QUESTION_RESULTS_RAW, 95)
    assert results == QUESTION_RESULTS


def test_parse_question(requests_mock):
    client = Client(BASE_URL, 'username', 'password', 'domain')
    requests_mock.post(BASE_URL + 'session/login', json={'data': {'session': 'session-id'}})
    requests_mock.post(BASE_URL + 'parse_question', json=parse_question_Folder_Contents_res)
    requests_mock.get(BASE_URL + 'sensors/by-name/Folder-Contents', json=sensor_res)

    results = client.parse_question(r'Get Folder-Contents[c:\] from all machines', '')
    assert results['selects'][0]['sensor']['name'] == 'Folder-Contents'
    assert results['selects'][0]['sensor']['parameters'][0]['key'] == '||folderPath||'
    assert results['selects'][0]['sensor']['parameters'][0]['value'] == 'c:\\'


def test_get_question_result_invalid_input():
    client = Client(BASE_URL, 'username', 'password', 'domain')
    data_args = {'completion-percentage': '0'}
    try:
        _, _, _ = get_question_result(client, data_args)
    except ValueError as e:
        assert str(e) == 'completion-percentage argument is invalid, Please enter number between 1 to 100'


data_test_parse_action_parameters = [
    ('key1=value1', [{'key': 'key1', 'value': 'value1'}]),
    ('key1=value1=value1', [{'key': 'key1', 'value': 'value1=value1'}]),
    ('key1=value1=value1;key2=value2', [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'value2'}]),
    ('key1=value1=value1;key2=valu;e2', [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'valu;e2'}]),
    ('key1=value1=value1;key2=ab=;c', [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'ab=;c'}])

]


@ pytest.mark.parametrize('parameters, accepted_result', data_test_parse_action_parameters)
def test_parse_action_parameters(parameters, accepted_result):
    """Tests parse_action_parameters function
    Given
        A string representing a key=value list separated by ';'
        1. parameters = 'key1=value1'
        2. parameters = 'key1=value1=value1'
        3. parameters = 'key1=value1=value1;key2=value2'
        4. parameters = 'key1=value1=value1;key2=valu;e2'
        5. parameters = key1=value1=value1;key2=ab=;c'

    When
        When calling the "parse_action_parameters" function to extract it to a dictionary
    Then
        validate that everything is extracted properly even if there is within the value "=" or ";"
        1. Ensure result = [{'key': 'key1', 'value': 'value1'}]
        2. Ensure result = [{'key': 'key1', 'value': 'value1=value1'}]
        3. Ensure result = [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'value2'}]
        4. Ensure result = [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'valu;e2'}]
        5. Ensure result = [{'key': 'key1', 'value': 'value1=value1'}, {'key': 'key2', 'value': 'ab=;c'}]
    """
    client = Client(BASE_URL, 'username', 'password', 'domain')
    result = client.parse_action_parameters(parameters)
    assert result == accepted_result


def test_update_session(mocker):
    """
    Tests the authentication method, based on the instance configurations.
    Given:
        - A client created using username and password
        - A client created using an API token
    When:
        - calling the update_session() function of the client
    Then:
        - Verify that the session was created using basic authentication
        - Verify that the session was created using oauth authentication
    """
    client = Client(BASE_URL, username='abdc', password='1234', domain='domain', api_token='')
    mocker.patch.object(Client, '_http_request', return_value={'data': {'session': 'basic authentication'}})
    client.update_session()
    assert client.session == 'basic authentication'

    client = Client(BASE_URL, username='', password='', domain='domain', api_token='oauth authentication')
    client.update_session()
    assert client.session == 'oauth authentication'


def test_get_action_result(mocker):
    """
    Tests the get action result method.
    Given:
        - Action ID to get information on.
    When:
        - calling the get_action_result() function.
    Then:
        - Verify that the human_readable was created as expected.
        - Verify that the outputs was created as expected.
        - Verify that the raw_response was created as expected.
    """
    client = Client(BASE_URL, 'username', 'password', 'domain')
    data_args = {'id': '350385'}
    action_res = get_fetch_data()
    mocker.patch.object(Client, 'do_request', return_value=action_res['action_raw_response'])
    human_readable, outputs, action_res_outputs = get_action_result(client, data_args)
    assert action_res_outputs == action_res['action_output']
    assert outputs == action_res['action_output_res']
    assert '### Device Statuses' in human_readable
