from IllusiveNetworks import Client, is_deceptive_user_command, is_deceptive_server_command,\
    delete_deceptive_users_command, delete_deceptive_servers_command, run_forensics_on_demand_command, \
    get_asm_host_insight_command, get_asm_cj_insight_command, get_deceptive_users_command, \
    get_deceptive_servers_command, get_forensics_timeline_command, assign_host_to_policy_command, \
    remove_host_from_policy_command, add_deceptive_users_command, add_deceptive_servers_command, \
    get_incidents_command, get_event_incident_id_command, fetch_incidents, get_incident_events_command, \
    get_forensics_analyzers_command, get_forensics_triggering_process_info_command, get_forensics_artifacts_command

from CommonServerPython import parse_date_range

DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.000Z'


def test_is_deceptive_user_command_returns_true(requests_mock):
    mock_response = {'result': 'true'}
    requests_mock.get('https://server/api/v1/deceptive-entities/user?userName=myUser', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'username': 'myUser'
    }
    _, outputs, _ = is_deceptive_user_command(client, args)

    assert outputs['Illusive.IsDeceptive(val.Username == obj.Username)']['Username'] == args['username']
    assert outputs['Illusive.IsDeceptive(val.Username == obj.Username)']['IsDeceptiveUser'] is True


def test_is_deceptive_user_command_returns_false(requests_mock):
    requests_mock.get('https://server/api/v1/deceptive-entities/user?userName=myUser', text='')

    client = Client(base_url='https://server', verify=False)
    args = {
        'username': 'myUser'
    }
    _, outputs, _ = is_deceptive_user_command(client, args)

    assert outputs['Illusive.IsDeceptive(val.Username == obj.Username)']['Username'] == args['username']
    assert outputs['Illusive.IsDeceptive(val.Username == obj.Username)']['IsDeceptiveUser'] is False


def test_is_deceptive_server_command_returns_true(requests_mock):
    mock_response = {'result': 'true'}
    requests_mock.get('https://server/api/v1/deceptive-entities/server?hostName=myHost', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'hostname': 'myHost'
    }
    _, outputs, _ = is_deceptive_server_command(client, args)

    assert outputs['Illusive.IsDeceptive(val.Hostname == obj.Hostname)']['Hostname'] == args['hostname']
    assert outputs['Illusive.IsDeceptive(val.Hostname == obj.Hostname)']['IsDeceptiveServer'] is True


def test_is_deceptive_server_command_returns_false(requests_mock):
    requests_mock.get('https://server/api/v1/deceptive-entities/server?hostName=myHost', text='')

    client = Client(base_url='https://server', verify=False)
    args = {
        'hostname': 'myHost'
    }
    _, outputs, _ = is_deceptive_server_command(client, args)

    assert outputs['Illusive.IsDeceptive(val.Hostname == obj.Hostname)']['Hostname'] == args['hostname']
    assert outputs['Illusive.IsDeceptive(val.Hostname == obj.Hostname)']['IsDeceptiveServer'] is False


def test_delete_deceptive_users_command(requests_mock):
    mock_response = {'result': 'False'}
    requests_mock.delete('https://server/api/v1/deceptive-entities/users?deceptive_users=user1&deceptive_users=user2',
                         json=mock_response)

    client = Client(base_url='https://server', verify=False)

    args = {
        'deceptive_users': ['user1', 'user2']
    }
    _, outputs, _ = delete_deceptive_users_command(client, args)

    assert outputs == {}


def test_delete_deceptive_servers_command(requests_mock):
    mock_response = {'result': 'False'}
    requests_mock.delete('https://server/api/v1/deceptive-entities/servers?deceptive_hosts=server1', json=mock_response)

    client = Client(base_url='https://server', verify=False)

    args = {
        'deceptive_hosts': ['server1']
    }
    _, outputs, _ = delete_deceptive_servers_command(client, args)

    assert outputs == {}


def test_run_forensics_on_demand_command(requests_mock):
    mock_response = {'EventId': '1234'}
    requests_mock.post('https://server/api/v1/event/create-external-event?hostNameOrIp=myIp', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'fqdn_or_ip': "myIp"
    }
    _, outputs, _ = run_forensics_on_demand_command(client, args)

    assert outputs == {'Illusive.Event(val.eventId == obj.eventId)': {'EventId': '1234'}}


def test_get_event_incident_id_command(requests_mock):
    mock_response = {'EventId': '1234', 'IncidentId': '1'}
    requests_mock.get('https://server/api/v1/incidents/id?event_id=1234', json=mock_response)

    client = Client(base_url='https://server', verify=False)

    args = {
        'event_id': "1234"
    }
    _, outputs, _ = get_event_incident_id_command(client, args)

    assert outputs == {'Illusive.Event(val.eventId == obj.eventId)':
                       [{'eventId': 1234, 'incidentId': {'EventId': '1234', 'IncidentId': '1'},
                        'status': 'Done'}]}


def test_get_asm_host_insight_command(requests_mock):
    mock_response = {'hostname': 'aaa', 'domainName': 'bbb', 'ipAddresses': '1.1.1.1'}
    requests_mock.get('https://server/api/v1/attack-surface/machine-insights?hostNameOrIp=myIp',
                      json=mock_response, status_code=202)

    client = Client(base_url='https://server', verify=False)

    args = {
        'hostnameOrIp': "myIp"
    }
    _, outputs, _ = get_asm_host_insight_command(client, args)

    assert outputs == {'Illusive.AttackSurfaceInsightsHost(val.ipAddresses == obj.ipAddresses)':
                       {'hostname': 'aaa', 'domainName': 'bbb', 'ipAddresses': '1.1.1.1'}}


def test_get_asm_cj_insight_command(requests_mock):
    mock_response = {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}
    requests_mock.get('https://server/api/v1/crownjewels/insights', json=mock_response, status_code=202)

    client = Client(base_url='https://server', verify=False)

    args = {
    }
    _, outputs, _ = get_asm_cj_insight_command(client, args)

    assert outputs == {'Illusive.AttackSurfaceInsightsCrownJewel(val.hostname == obj.hostname)':
                       {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}}


def test_get_deceptive_users_command(requests_mock):
    mock_response = {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}
    requests_mock.get('https://server/api/v1/deceptive-entities/users?deceptive_user_type=ALL', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
    }
    _, outputs, _ = get_deceptive_users_command(client, args)

    assert outputs == {'Illusive.DeceptiveUser(val.userName == obj.userName)':
                       {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}}


def test_get_deceptive_servers_command(requests_mock):
    mock_response = {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}
    requests_mock.get('https://server/api/v1/deceptive-entities/servers?deceptive_server_type=SUGGESTED',
                      json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'type': "SUGGESTED",
    }
    _, outputs, _ = get_deceptive_servers_command(client, args)

    assert outputs == {'Illusive.DeceptiveServer(val.host == obj.host)':
                       {'data': [], 'hostname': 'bbb', 'machineTagAndSubTags': {'tag': 'tag', 'subTag': 'sub'}}}


def test_get_forensics_timeline_command(requests_mock):
    mock_response = [{'IncidentId': "aaa", 'Status': 'Done', 'details': {'date': 'aaa'}}]
    client = Client(base_url='https://server', verify=False)
    start_date = "1 month"
    end_date = "3 days"
    args = {
        'incident_id': "3",
        'start_date': start_date,
        'end_date': end_date
    }
    start_date_parsed, _ = parse_date_range(start_date, date_format=DATE_FORMAT, utc=True)
    end_date_parsed, _ = parse_date_range(end_date, date_format=DATE_FORMAT, utc=True)
    url = 'https://server/api/v1/forensics/timeline?incident_id=3&end_date={}&start_date={}'\
        .format(end_date_parsed, start_date_parsed)
    requests_mock.get(url, json=mock_response)
    _, outputs, _ = get_forensics_timeline_command(client, args)

    assert outputs == {'Illusive.Forensics(val.IncidentId == obj.IncidentId)':
                       {'IncidentId': '3', 'Status': 'Done', 'Evidence':
                        [{'IncidentId': 'aaa', 'Status': 'Done', 'details': {'date': 'aaa'}, 'date': 'aaa'}]}}


def test_remove_host_from_policy_command(requests_mock):
    mock_response = {'result': 'True'}
    requests_mock.post('https://server/api/v1/policy/domain_hosts/remove_assignment', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'hosts': ['aaa@domain.com']
    }
    _, outputs, _ = remove_host_from_policy_command(client, args)

    assert outputs == {'Illusive.DeceptionPolicy.isAssigned(val.hosts == obj.hosts)':
                       [{'isAssigned': False, 'hosts': 'aaa@domain.com', 'policy_name': ''}]}


def test_assign_host_to_policy_command(requests_mock):
    mock_response = {'result': 'True'}
    requests_mock.post('https://server/api/v1/policy/domain_hosts/assign?policy_name=myPolicy', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'policy_name': "myPolicy",
        'hosts': ['aaa@domain.com']
    }

    _, outputs, _ = assign_host_to_policy_command(client, args)

    assert outputs == {'Illusive.DeceptionPolicy.isAssigned(val.hosts == obj.hosts)':
                       [{'isAssigned': True, 'hosts': 'aaa@domain.com', 'policy_name': 'myPolicy'}]}


def test_add_deceptive_users_command(requests_mock):
    mock_response = {'id': 'aaa'}
    requests_mock.post('https://server/api/v1/deceptive-entities/users', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    user_name = "aaa"
    domain_name = "illusive.com"
    args = {
        'password': "aaa",
        'username': user_name,
        'domain_name': domain_name,
        'policy_names': ["myPolicy"]
    }

    _, outputs, _ = add_deceptive_users_command(client, args)

    assert outputs == {'Illusive.DeceptiveUser(val.userName == obj.userName)':
                       {'userName': 'aaa', 'domainName': 'illusive.com', 'policyNames': ['myPolicy'], 'password': 'aaa'}}


def test_add_deceptive_servers_command(requests_mock):
    mock_response = {'id': 'aaa'}
    requests_mock.post('https://server/api/v1/deceptive-entities/servers', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    user_name = 'aaa.illusive.com'
    args = {
        'service_types': ["FTP", "SSH"],
        'host': user_name
    }

    _, outputs, _ = add_deceptive_servers_command(client, args)

    assert outputs == {'Illusive.DeceptiveServer(val.host == obj.host)':
                       {'host': 'aaa.illusive.com', 'serviceTypes': ['FTP', 'SSH'], 'policyNames': "All Policies"}}


def test_get_incident_command(requests_mock):
    mock_response = {'deceptionFamilies': [], 'incidentId': '1234', 'hasForensics': True, 'incidentTypes': 'MACHINE'}
    requests_mock.get('https://server/api/v2/incidents/incident?incident_id=13', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'incident_id': "13",
        'start_date': "3 days"
    }
    _, outputs, _ = get_incidents_command(client, args)

    assert outputs == {'Illusive.Incident(val.incidentId == obj.incidentId)':
                       {'deceptionFamilies': [], 'incidentId': '1234', 'hasForensics': True, 'incidentTypes': 'MACHINE'}}


def test_get_incidents_command(requests_mock):
    mock_response = [{'deceptionFamilies': [], 'incidentId': '1234', 'hasForensics': True, 'incidentTypes': 'MACHINE'},
                     {'deceptionFamilies': [], 'incidentId': '4321', 'hasForensics': False, 'incidentTypes': 'MACHINE'}]
    requests_mock.get('https://server/api/v1/incidents?limit=10&offset=0', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
    }
    _, outputs, _ = get_incidents_command(client, args)

    assert outputs == {'Illusive.Incident(val.incidentId == obj.incidentId)': [
                      {'deceptionFamilies': [], 'incidentId': '1234', 'hasForensics': True, 'incidentTypes': 'MACHINE'},
                      {'deceptionFamilies': [], 'incidentId': '4321', 'hasForensics': False, 'incidentTypes': 'MACHINE'}
    ]}


def test_fetch_incidents(requests_mock):
    client = Client(base_url='https://server', verify=False)
    mock_response = [{'deceptionFamilies': [], 'incidentId': '1234', 'hasForensics': True,
                      'incidentTypes': 'MACHINE', 'incidentTimeUTC': '2020-04-21T15:39:32.954Z'},
                     {'deceptionFamilies': [], 'incidentId': '4321', 'hasForensics':False,
                     'incidentTypes': 'MACHINE', 'incidentTimeUTC': '2020-04-21T14:53:54.234Z'}]
    first_fetch_time = "7 days"
    requests_mock.get('https://server/api/v1/incidents?limit=10&offset=0&start_date=2018-10-24T14:13:20+00:000Z',
                      json=mock_response)
    nextcheck, incidents = fetch_incidents(client, {'last_run': "2018-10-24T14:13:20+00:000Z"}, first_fetch_time, None)

    assert str(nextcheck['last_run']) == '2020-04-21T15:39:32.954Z'
    assert isinstance(incidents, list)
    assert isinstance(incidents[0]['name'], str)


def test_fetch_incidents_first_fetch(requests_mock):
    client = Client(base_url='https://server', verify=False)
    mock_response = []
    first_fetch_time = "7 days"
    last_fetch, _ = parse_date_range(first_fetch_time, date_format=DATE_FORMAT, utc=True)
    requests_mock.get('https://server/api/v1/incidents?limit=10&offset=0&start_date={}'.format(last_fetch),
                      json=mock_response)
    nextcheck, incidents = fetch_incidents(client, {'last_run': None}, first_fetch_time, None)

    assert str(nextcheck['last_run']) == last_fetch
    assert isinstance(incidents, list)
    assert len(incidents) == 0


def test_get_incident_events_command(requests_mock):
    mock_response = [{'eventId': '11', 'eventTimeUTC': '1234', 'hasForensics': True},
                     {'eventId': '22', 'eventTimeUTC': '1234', 'hasForensics': True}]
    requests_mock.get('https://server/api/v1/incidents/events?incident_id=3&limit=100&offset=0', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'incident_id': '3'
    }
    _, outputs, _ = get_incident_events_command(client, args)

    assert outputs == {'Illusive.Incident(val.incidentId == obj.incidentId)': {'Event': [
                      {'eventId': '11', 'eventTimeUTC': '1234', 'hasForensics': True},
                      {'eventId': '22', 'eventTimeUTC': '1234', 'hasForensics': True}],
        'eventsNumber': 2, 'incidentId': 3}}


def test_get_forensics_analyzers_command(requests_mock):
    mock_response1 = [{'analyzerName': 'bbb', 'analyzerValue': '1234'},
                      {'analyzerName': 'aaa', 'analyzerValue': '4321'}]
    mock_response2 = 3
    requests_mock.get('https://server/api/v1/forensics/analyzers?event_id=3', json=mock_response1)
    requests_mock.get('https://server/api/v1/incidents/id?event_id=3', json=mock_response2)

    client = Client(base_url='https://server', verify=False)
    args = {
        'event_id': '3'
    }
    _, outputs, _ = get_forensics_analyzers_command(client, args)

    assert outputs == {'Illusive.Event(val.eventId == obj.eventId)': {'ForensicsAnalyzers':
                       [{'analyzerName': 'bbb', 'analyzerValue': '1234'},
                        {'analyzerName': 'aaa', 'analyzerValue': '4321'}], 'eventId': 3, 'incidentId': 3}}


def test_get_forensics_triggering_process_info_command(requests_mock):
    mock_response = {'processes': [{'commandLine': 'bbb', 'name': '1234', 'parent': '1234', 'sha256': '1234'},
                     {'commandLine': 'aaa', 'name': '34556', 'parent': 'dfg', 'sha256': 'erf'}]}
    requests_mock.get('https://server/api/v1/forensics/triggering_process_info?event_id=3', json=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'event_id': '3'
    }
    _, outputs, _ = get_forensics_triggering_process_info_command(client, args)

    assert outputs == {'Illusive.Event(val.eventId == obj.eventId)': {'ForensicsTriggeringProcess': [
                      {'commandLine': 'bbb', 'name': '1234', 'parent': '1234', 'sha256': '1234'},
                      {'commandLine': 'aaa', 'name': '34556', 'parent': 'dfg', 'sha256': 'erf'}], 'eventId': '3'}}


def test_get_forensics_artifacts_command(requests_mock):
    mock_response = bytes()
    mock_response2 = 3
    requests_mock.get('https://server/api/v1/incidents/id?event_id=3', json=mock_response2)
    requests_mock.get('https://server/api/v1/forensics/artifacts?event_id=3&artifacts_type=DESKTOP_SCREENSHOT',
                      content=mock_response)

    client = Client(base_url='https://server', verify=False)
    args = {
        'event_id': '3',
        'artifact_type': 'DESKTOP_SCREENSHOT'
    }
    get_forensics_artifacts_command(client, args)
