import os
import json
import demistomock as demisto
from tempfile import mkdtemp
from Anomali_ThreatStream_v2 import main, file_name_to_valid_string, get_file_reputation, Client, get_indicators
import emoji
import pytest


def util_load_json(path):
    with open(path, mode='r', encoding='utf-8') as f:
        return json.loads(f.read())


def http_request_with_approval_mock(req_type, suffix, params, data=None, files=None):
    return {
        'success': True,
        'import_session_id': params,
        'data': data,
    }


def http_request_without_approval_mock(req_type, suffix, params, data=None, files=None, json=None, text_response=None):
    return {
        'success': True,
        'import_session_id': 1,
        'files': files
    }


package_500_error = {
    'import_type': 'url',
    'import_value': 'www.demisto.com',
}

expected_output_500 = {
    'Contents': {
        'data': {
            'classification': 'Private',
            'confidence': 50,
            'severity': 'low',
            'threat_type': 'exploit',
            'url': 'www.demisto.com'
        },
        'import_session_id': {
            'api_key': None,
            'username': None
        },
        'success': True
    },
    'ContentsFormat': 'json',
    'EntryContext': {
        'ThreatStream.Import.ImportID': {
            'api_key': None,
            'datatext': 'www.demisto.com',
            'username': None
        }
    },
    'HumanReadable': 'The data was imported successfully. The ID of imported job '
                     "is: {'datatext': 'www.demisto.com', 'username': None, "
                     "'api_key': None}",
    'Type': 1
}

mock_objects = {"objects": [{"srcip": "8.8.8.8", "itype": "mal_ip", "confidence": 50},
                            {"srcip": "1.1.1.1", "itype": "apt_ip"}]}

expected_import_json = {'objects': [{'srcip': '8.8.8.8', 'itype': 'mal_ip', 'confidence': 50},
                                    {'srcip': '1.1.1.1', 'itype': 'apt_ip'}],
                        'meta': {'classification': 'private', 'confidence': 30, 'allow_unresolved': False}}

INDICATOR = [{
    "resource_uri": "/api/v2/intelligence/123456789/",
    "status": "active",
    "uuid": "12345678-dead-beef-a6cc-eeece19516f6",
    "value": "www.demisto.com",
}]


def test_ioc_approval_500_error(mocker):
    mocker.patch.object(Client, 'http_request', side_effect=http_request_with_approval_mock)
    mocker.patch.object(demisto, 'args', return_value=package_500_error)
    mocker.patch.object(demisto, 'command', return_value='threatstream-import-indicator-with-approval')
    mocker.patch.object(demisto, 'results')

    main()
    results = demisto.results.call_args[0]

    assert results[0]['Contents']['data'] == expected_output_500['Contents']['data']


def test_emoji_handling_in_file_name():
    file_names_package = ['Fwd for you 😍', 'Hi all', '', '🐝🤣🇮🇱👨🏽‍🚀🧟‍♂🧞‍♂🧚🏼‍♀', '🧔🤸🏻‍♀🥩🧚😷🍙👻']

    for file_name in file_names_package:
        demojized_file_name = file_name_to_valid_string(file_name)
        assert demojized_file_name == emoji.demojize(file_name)
        assert not emoji.emoji_count(file_name_to_valid_string(demojized_file_name))


def test_import_ioc_without_approval(mocker):
    tmp_dir = mkdtemp()
    file_name = 'test_file.txt'
    file_obj = {
        'name': file_name,
        'path': os.path.join(tmp_dir, file_name)
    }
    with open(file_obj['path'], 'w') as f:
        json.dump(mock_objects, f)
    http_mock = mocker.patch.object(Client, 'http_request', side_effect=http_request_without_approval_mock)
    mocker.patch.object(demisto, 'args', return_value={'file_id': 1, 'classification': 'private',
                                                       'allow_unresolved': 'no', 'confidence': 30})
    mocker.patch.object(demisto, 'command', return_value='threatstream-import-indicator-without-approval')
    mocker.patch.object(demisto, 'results')
    mocker.patch.object(demisto, 'getFilePath', return_value=file_obj)

    main()
    results = demisto.results.call_args[0]

    assert results[0]['Contents']
    assert expected_import_json == http_mock.call_args[1]['json']


SHA_256_FILE_HASH = '178ba564b39bd07577e974a9b677dfd86ffa1f1d0299dfd958eb883c5ef6c3e1'
SHA_512_FILE_HASH = '665564674b6b4a7a3a69697221acef98ee5ca3664ce6b370059cb7d3b0942589556e5a9d69d83d038339535ea4ced2d4d' \
                    '300e07013a16'


@pytest.mark.parametrize('file_hash, expected_result_file_path, raw_response_file_path', [
    (SHA_256_FILE_HASH,
     'test_data/file_256_context.json',
     'test_data/file_256_response.json'),
    (SHA_512_FILE_HASH,
     'test_data/file_512_context.json',
     'test_data/file_512_response.json')
])
def test_get_file_reputation(mocker, file_hash, expected_result_file_path, raw_response_file_path):
    expected_result = util_load_json(expected_result_file_path)
    raw_response = util_load_json(raw_response_file_path)
    mocker.patch('Anomali_ThreatStream_v2.search_indicator_by_params', return_value=raw_response)
    mocker.patch.object(demisto, 'results')

    client = Client(
        base_url='',
        use_ssl=False,
        default_threshold='high',
        reliability='B - Usually reliable'
    )

    get_file_reputation(client, file_hash)
    context = demisto.results.call_args_list[0][0][0].get('EntryContext')

    assert context == expected_result


class TestGetIndicators:
    @staticmethod
    def test_sanity(mocker):
        """
        Given
            a limit above the number of available indicators
        When
            calling the get_indicator command
        Then
            verify that the maximum available amount is returned.
        """
        mocker.patch.object(Client, 'http_request', side_effect=[
            {'objects': INDICATOR * 50},
            {'objects': []},
        ])
        results = mocker.patch.object(demisto, 'results')
        client = Client(
            base_url='',
            use_ssl=False,
            default_threshold='high',
            reliability='B - Usually reliable',
        )

        get_indicators(client, limit='7000')

        assert len(results.call_args_list[0][0][0].get('EntryContext', {}).get('ThreatStream.Indicators', [])) == 50

    @staticmethod
    def test_pagination(mocker):
        """
        Given
            a limit above the page size
        When
            calling the get_indicator command
        Then
            verify that the requested amount is returned.
        """
        mocker.patch.object(Client, 'http_request', side_effect=[
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
            {'objects': INDICATOR * 1000},
        ])
        results = mocker.patch.object(demisto, 'results')
        client = Client(
            base_url='',
            use_ssl=False,
            default_threshold='high',
            reliability='B - Usually reliable',
        )

        get_indicators(client, limit='7000')

        assert len(results.call_args_list[0][0][0].get('EntryContext', {}).get('ThreatStream.Indicators', [])) == 7000
