import demistomock as demisto
from CommonServerPython import *
from CommonServerUserPython import *

''' IMPORTS '''
import requests
from typing import Tuple, Any
import json

# Disable insecure warnings
requests.packages.urllib3.disable_warnings()


''' GLOBAL VARS '''

SPECIAL_HEADERS: dict = {
    'id': 'ID',
    'userId': 'User ID',
    'osVersion': 'OS Version',
    'imei': 'IMEI',
    'meid': 'MEID'
}

HEADERS: dict = {
    'raw_device': ['id', 'userId', 'deviceName', 'operatingSystem', 'osVersion', 'emailAddress',
                   'manufacturer', 'model', 'imei', 'meid'],
}


''' CLIENT '''


class MsGraphClient:
    def __init__(self, self_deployed, tenant_id, auth_and_token_url, enc_key, app_name, base_url, use_ssl, proxy,
                 ok_codes):
        self.ms_client = MicrosoftClient(self_deployed=self_deployed, tenant_id=tenant_id, auth_id=auth_and_token_url,
                                         enc_key=enc_key, app_name=app_name, base_url=base_url, verify=use_ssl,
                                         proxy=proxy, ok_codes=ok_codes)

    def list_managed_devices(self, limit: int) -> Tuple[list, Any]:
        url_suffix: str = '/deviceManagement/managedDevices'
        raw_response = self.ms_client.http_request('GET', url_suffix)
        return raw_response.get('value', [])[:limit], raw_response

    def get_managed_device(self, device_id: str) -> Tuple[Any, str]:
        url_suffix: str = f'/deviceManagement/managedDevices/{device_id}'
        return self.ms_client.http_request('GET', url_suffix), device_id

    def make_action(self, device_id: str, action: str, body: str = None) -> None:
        url_suffix: str = f'deviceManagement/managedDevices/{device_id}/{action}'
        self.ms_client.http_request('POST', url_suffix, data=body, return_empty_response=True)

    def delete_user_from_shared_apple_device(self, user_principal_name: str, device_id: str, action: str) -> None:
        body: dict = {'userPrincipalName': user_principal_name}
        self.make_action(device_id, action, json.dumps(body))

    def clean_windows_device(self, keep_user_data: bool, device_id: str, action: str) -> None:
        body: dict = {'keepUserData': keep_user_data}
        self.make_action(device_id, action, json.dumps(body))

    def windows_device_defender_scan(self, quick_scan: bool, device_id: str, action: str) -> None:
        body: dict = {'quickScan': quick_scan}
        self.make_action(device_id, action, json.dumps(body))

    def wipe_device(self, keep_enrollment_data: bool, keep_user_data: bool, mac_os_unlock_code: str,
                    device_id: str, action: str) -> None:
        body: dict = {
            'keepEnrollmentData': keep_enrollment_data,
            'keepUserData': keep_user_data
        }
        if mac_os_unlock_code:
            body['macOsUnlockCode'] = mac_os_unlock_code
        self.make_action(device_id, action, json.dumps(body))

    def update_windows_device_account(self, device_account_password: str, password_rotation_enabled: bool,
                                      calendar_sync_enabled: bool, device_account_email: str, exchange_server: str,
                                      session_initiation_protocal_address: str, device_id: str, action: str) -> None:
        body: dict = {
            'updateWindowsDeviceAccountActionParameter': {
                '@odata.type': 'microsoft.graph.updateWindowsDeviceAccountActionParameter',
                'deviceAccount': {
                    '@odata.type': 'microsoft.graph.windowsDeviceAccount',
                    'password': device_account_password
                },
                'passwordRotationEnabled': password_rotation_enabled,
                'calendarSyncEnabled': calendar_sync_enabled,
                'deviceAccountEmail': device_account_email,
                'exchangeServer': exchange_server,
                'sessionInitiationProtocalAddress': session_initiation_protocal_address
            }
        }
        self.make_action(device_id, action, json.dumps(body))


''' HELPER FUNCTIONS '''


def try_parse_integer(int_to_parse: Any, err_msg: str) -> int:
    """
    Tries to parse an integer, and if fails will throw DemistoException with given err_msg
    :param int_to_parse: The argument to be parsed into integer
    :param err_msg: The error message to show in case of failure
    :return: The integer
    """
    try:
        res: int = int(int_to_parse)
    except (TypeError, ValueError):
        raise DemistoException(err_msg)
    return res


def parse_device_action_results(raw_device_action_results: list) -> list:
    """
    Parses a list of device action results
    :param raw_device_action_results: The raw list of device action results
    :return: The parsed list of device action results
    """
    action_results: list = list()
    for device_action_result in raw_device_action_results:
        action_result = assign_params(**{
            'Name': device_action_result.get('actionName'),
            'State': device_action_result.get('actionState'),
            'StartDateTime': device_action_result.get('startDateTime'),
            'LastUpdatedDateTime': device_action_result.get('lastUpdatedDateTime')
        })
        if action_result:
            action_results.append(action_result)
    return action_results


def build_device_object(raw_device: dict) -> dict:
    """
    Builds a device context object
    :param raw_device: The raw device object
    :return: The device context object
    """
    device_action_results: list = raw_device.get('deviceActionResults', []) if raw_device.get('deviceActionResults') \
        else []
    conf_manager_client_enabled_features: dict = raw_device.get('configurationManagerClientEnabledFeatures', {}) \
        if raw_device.get('configurationManagerClientEnabledFeatures') else {}
    device_health_attestation_state: dict = raw_device.get('deviceHealthAttestationState', {}) \
        if raw_device.get('deviceHealthAttestationState') else {}
    return assign_params(**{
        'ID': raw_device.get('id'),
        'UserID': raw_device.get('userId'),
        'Name': raw_device.get('deviceName'),
        'ManagedDeviceOwnerType': raw_device.get('managedDeviceOwnerType'),
        'ActionResults': parse_device_action_results(device_action_results),
        'EnrolledDateTime': raw_device.get('enrolledDateTime'),
        'LastSyncDateTime': raw_device.get('lastSyncDateTime'),
        'OperatingSystem': raw_device.get('operatingSystem'),
        'ComplianceState': raw_device.get('complianceState'),
        'JailBroken': raw_device.get('jailBroken'),
        'ManagementAgent': raw_device.get('managementAgent'),
        'OSVersion': raw_device.get('osVersion'),
        'EASDeviceID': raw_device.get('easDeviceId'),
        'EASActivationDateTime': raw_device.get('easActivationDateTime'),
        'ActivationLockBypassCode': raw_device.get('activationLockBypassCode'),
        'EmailAddress': raw_device.get('emailAddress'),
        'AzureADDeviceID': raw_device.get('azureADDeviceId'),
        'CategoryDisplayName': raw_device.get('deviceCategoryDisplayName'),
        'ExchangeAccessState': raw_device.get('exchangeAccessState'),
        'ExchangeAccessStateReason': raw_device.get('exchangeAccessStateReason'),
        'IsSupervised': raw_device.get('isSupervised'),
        'IsEncrypted': raw_device.get('isEncrypted'),
        'UserPrincipalName': raw_device.get('userPrincipalName'),
        'Model': raw_device.get('model'),
        'Manufacturer': raw_device.get('manufacturer'),
        'IMEI': raw_device.get('imei'),
        'SerialNumber': raw_device.get('serialNumber'),
        'PhoneNumber': raw_device.get('phoneNumber'),
        'AndroidSecurityPatchLevel': raw_device.get('androidSecurityPatchLevel'),
        'ConfigurationManagerClientEnabledFeatures': assign_params(**{
            'Inventory': conf_manager_client_enabled_features.get('inventory'),
            'ModernApps': conf_manager_client_enabled_features.get('modernApps'),
            'ResourceAccess': conf_manager_client_enabled_features.get('resourceAccess'),
            'DeviceConfiguration': conf_manager_client_enabled_features.get('deviceConfiguration'),
            'CompliancePolicy': conf_manager_client_enabled_features.get('compliancePolicy'),
            'WindowsUpdateForBusiness': conf_manager_client_enabled_features.get('windowsUpdatesForBusiness')
        }),
        'WiFiMacAddress': raw_device.get('wiFiMacAddress'),
        'HealthAttestationState': assign_params(**{
            'LastUpdateDateTime': device_health_attestation_state.get('lastUpdateDateTime'),
            'IssuedDateTime': device_health_attestation_state.get('issuedDateTime'),
            'ResetCount': device_health_attestation_state.get('resetCount'),
            'RestartCount': device_health_attestation_state.get('restartCount'),
            'BitLockerStatus': device_health_attestation_state.get('bitLockerStatus'),
            'BootManagerVersion': device_health_attestation_state.get('bootManagerVersion'),
            'SecureBoot': device_health_attestation_state.get('secureBoot'),
            'BootDebugging': device_health_attestation_state.get('bootDebugging'),
            'OperatingSystemKernelDebugging': device_health_attestation_state.get('operatingSystemKernelDebugging'),
            'CodeIntegrity': device_health_attestation_state.get('codeIntegrity'),
            'TestSigning': device_health_attestation_state.get('testSigning'),
            'SafeMode': device_health_attestation_state.get('safeMode'),
            'WindowsPE': device_health_attestation_state.get('windowsPE'),
            'EarlyLaunchAntiMalwareDriverProtection':
                device_health_attestation_state.get('earlyLaunchAntiMalwareDriverProtection'),
            'VirtualSecureMode': device_health_attestation_state.get('virtualSecureMode'),
            'PCRHashAlgorithm': device_health_attestation_state.get('pcrHashAlgorithm'),
            'BootAppSecurityVersion': device_health_attestation_state.get('bootAppSecurityVersion'),
            'BootManagerSecurityVersion': device_health_attestation_state.get('bootManagerSecurityVersion'),
            'TPMVersion': device_health_attestation_state.get('tpmVersion'),
            'PCR0': device_health_attestation_state.get('pcr0'),
            'SecureBootConfigurationPolicyFingerPrint':
                device_health_attestation_state.get('secureBootConfigurationPolicyFingerPrint'),
            'CodeIntegrityPolicy': device_health_attestation_state.get('codeIntegrityPolicy'),
            'BootRevisionListInfo': device_health_attestation_state.get('bootRevisionListInfo'),
            'OperatingSystemRevListInfo': device_health_attestation_state.get('operatingSystemRevListInfo'),