from typing import Tuple

from CommonServerPython import *

''' STANDALONE FUNCTION '''

INCIDENT_ID = demisto.incident().get('id')

XDR_ACTIONS = {
    'allow': 'xdr-whitelist-files',
    'block': 'xdr-blacklist-files'
}

MSDE_ACTIONS = {
    'allow': 'Allowed',
    'block': 'AlertAndBlock',
}

CROWDSTRIKE_ACTIONS = {
    'allow': {'action': 'allow',
              'description': f'Whitelisted based on XSOAR inc {INCIDENT_ID}',
              'severity': 'low'},
    'block': {'action': 'prevent',
              'description': f'Blacklisted based on XSOAR inc {INCIDENT_ID}',
              'severity': 'high'}
}


def create_commands(hashes: List[str], action: str) -> List[CommandRunner.Command]:
    """
    Create a list of `Command` of the allow/block hash command to `Cortex XDR`, `CrowdstrikeFalcon`,
     `Microsoft Defender Advanced Threat Protection`

    :param hashes: The hashes list
    :param action: The action to have (one of {'allow', 'block'})
    :return: A list of `Command`
    """

    msde_action = MSDE_ACTIONS.get(action)
    crowdstrike_commands, crowdstrike_args_lst = get_crowdstrike_commands_args(hashes, action)
    return [CommandRunner.Command(commands=XDR_ACTIONS.get(action),
                                  args_lst={'hash_list': ','.join(hashes)}),
            CommandRunner.Command(commands='microsoft-atp-sc-indicator-create',
                                  args_lst=[{'indicator_value': h,
                                             'indicator_type': 'FileSha256',
                                             'action': msde_action,
                                             'indicator_description': f'XSOAR - related incident {INCIDENT_ID}',
                                             'indicator_title': f'XSOAR - related incident {INCIDENT_ID}'}
                                            for h in hashes]),
            CommandRunner.Command(commands=crowdstrike_commands,
                                  args_lst=crowdstrike_args_lst)
            ]


def get_crowdstrike_commands_args(hashes: List[str], action: str) -> Tuple[List[str], List[dict]]:
    """
    Get the commands and args that supposed to run the action on the hashes in CrowdstrikeFalcon

    :param hashes: The hashes list
    :param action: The action to have (one of {'allow', 'block'})
    :return: A tuple: first is a list of commands to run, and the second is the list of args to run
    """
    cs_search_command_executer = CommandRunner.Command(commands='cs-falcon-search-custom-iocs',
                                                       args_lst={'values': ','.join(hashes)},
                                                       brand='CrowdstrikeFalcon')
    search_results, errors_search = CommandRunner.execute_commands(
        cs_search_command_executer,
        extract_contents=True)
    commands, args_lst = [], []
    ioc_metadata = CROWDSTRIKE_ACTIONS[action]
    for search_res in search_results:
        search_results_hashes = [ioc.get('value') for ioc in search_res.result.get('resources', [])]
        new_hashes = [h for h in hashes if h not in search_results_hashes]
        for h in new_hashes:
            commands.append('cs-falcon-upload-custom-ioc')
            args_lst.append({'ioc_type': 'sha256',
                             'platforms': 'linux,mac,windows',
                             'applied_globally': 'true',
                             'value': h,
                             **ioc_metadata})
        for ioc in search_res.result.get('resources', []):
            commands.append('cs-falcon-update-custom-ioc')
            args_lst.append({'ioc_id': ioc.get('id'),
                             **ioc_metadata})
    return commands, args_lst


def run_hash_action(hashes: List[str], action: str) -> list:
    """
    Given arguments to the command, returns a list of results to return

    :param action: action to perform (allow or block)
    :param hashes: list of hashes

    :return: list of results to return
    :rtype: ``list``
    """
    commands = create_commands(hashes, action)
    return CommandRunner.run_commands_with_summary(commands)


''' MAIN FUNCTION '''


def main():  # pragma: no cover
    args = demisto.args()
    hashes = argToList(args.get('hash'))
    action = args.get('action')
    if not hashes:
        raise ValueError('hash not specified')
    if not action or action not in {'allow', 'block'}:
        raise ValueError('Action not specified or not in allowed actions')
    try:
        return_results(run_hash_action(hashes, action))
    except Exception as ex:
        return_error(f'Failed to execute HashWrapper. Error: {str(ex)}')


''' ENTRY POINT '''

if __name__ in ('__main__', '__builtin__', 'builtins'):
    main()
