import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
"""QutteraWebsiteMalwareScanner Integration for Cortex XSOAR (aka Demisto)
"""
import urllib3


# Disable insecure warnings
urllib3.disable_warnings()


''' CONSTANTS '''
DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ"


class Client(BaseClient):
    """Client class for basic interaction with Quttera API.
    """
    def __init__(self, params):
        self.apikey = params["apikey"]
        self.base_url = params["base_url"]
        super().__init__(base_url=self.base_url)

    def _api_request(self, domain: str, method: str, operation: str) -> Dict:
        """Start domain scanning

        :type domain: ``str``
        :param domain: Domain to scan

        :return: dict containing response from api request
        :rtype: ``Dict``
        """

        operations = {
            "scan": f"/api/v3/{self.apikey}/url/scan",
            "rescan": f"/api/v3/{self.apikey}/url/scan",
            "statscan": f"/api/v3/{self.apikey}/url/status",
            "malware": f"/api/v3/{self.apikey}/url/report",
            "blacklist": f"/api/v3/{self.apikey}/blacklist/status"
        }

        op = operations[operation]
        return self._http_request(
            method=method,
            url_suffix=f"{op}/{domain}",
            ok_codes=(200, 404)
        )

    def _test_module(self):
        return self._http_request(
            method="GET",
            url_suffix=f"/api/v3/{self.apikey}/status"
        )


def scan_start(client: Client, args: dict) -> CommandResults:
    """
    quttera-scan-start command: Scan a domain/website for malware and blacklist.

    :type client: ``Client`e
    :param Client: Qutter API client

    :type args: ``Dict[str, Any]``
    :param args: all command arguments from ``demisto.args()``

    :return: ``CommandResults`` object contain the start scan response
    :rtype: ``CommandResults``
    """
    domain = args.get("domain")
    if not domain:
        raise ValueError('domain is missing')

    start = client._api_request(domain=domain, method="POST", operation="scan")
    demisto.info(f"Start output {start}")
    readable_output = f'Started scan of {domain}. Run !quttera-report-malware to see the results.'
    if start.get('errorstr') != 'success':
        readable_output = f'Failed to scan domain {domain}'

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="QutteraWebsiteMalwareScanning.Start",
        outputs_key_field="error",
        outputs=start
    )


def rescan_status(client: Client, args: dict) -> CommandResults:
    """
    Retrieves scan status for previously submitted domain
    name or URL.

    """
    domain = args.get("domain")
    if not domain:
        raise ValueError('domain is missing')

    rescan = client._api_request(domain=domain, method="PUT", operation="rescan")
    readable_output = f'Rescan of {domain}'

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="QutteraWebsiteMalwareScanning.Status",
        outputs_key_field="error",
        outputs=rescan
    )


def scan_report(client: Client, args: dict) -> CommandResults:
    """
    Retrieves scan report for previously submitted domain
    or URL in context or as a File (default)

    """
    domain = args.get("domain")
    if not domain:
        raise ValueError('domain is missing')

    readable_output = "No output"
    report = client._api_request(domain=domain, method="GET", operation="statscan")

    state = None
    try:
        state = report["status"]["state"]
        states = ["NEW", "DOWNLOAD", "DOWNLOADED", "SCAN"]
        if state in states:
            readable_output = f"Domain {domain} is being scanned"
        else:
            status = report["status"]["scanner_result"]
            readable_output = f"Domain {domain} is {status}"
    except KeyError:
        readable_output = f"Domain {domain} was not scanned. Scan it with !quttera-scan-start domain={domain}"

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="QutteraWebsiteMalwareScanning.report",
        outputs_key_field="error"
    )


def report_malware(client: Client, args: dict) -> CommandResults:
    """
    Returns malware status for given url

    """
    url = args.get("url")
    if not url:
        raise ValueError('url is missing')

    scanned_files = None
    state = None
    full_report = None
    malware = client._api_request(domain=url, method="GET", operation="malware")
    apikey = client.apikey
    base_url = client.base_url
    try:
        scanned_files = malware["report"]["scanned_files"]
        state = malware["report"]["state"]
        headers = ("url", "status", "files", "full_report")
        full_report = f"{base_url}/api/v3/{apikey}/url/report/{url}",
        malware_data = {
            "url": url,
            "status": state,
            "files": scanned_files,
            "full_report": full_report
        }
        readable_output = tableToMarkdown(
            "Malware report",
            malware_data,
            headers=headers,
            headerTransform=string_to_table_header,
        )
    except KeyError:
        readable_output = f"Report is not ready or domain {url} was not scanned yet"

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="QutteraWebsiteMalwareScanning.malware",
        outputs_key_field="error",
        outputs=malware
    )


def status_blacklist(client: Client, args: dict) -> CommandResults:
    """
    Returns url blacklisting information and reputation.

    """
    domain = args.get("domain")
    if not domain:
        raise ValueError('domain is missing')

    blacklist = client._api_request(domain=domain, method="GET", operation="blacklist")
    readable_output = f"Domain {domain} is NOT blacklisted"
    if blacklist['status']['blacklisted'] == 'yes':
        readable_output = f"Domain {domain} is blacklisted"

    return CommandResults(
        readable_output=readable_output,
        outputs_prefix="",
        outputs_key_field='QutteraWebsiteMalwareScanning.report',
    )


def test_module(client: Client):
    """Performs basic request to ensure API server is running

    Return True if request succeeded
    """
    resp = client._test_module()
    if resp.get('errorstr') == 'success':
        return 'ok'
    raise DemistoException(f'Service is down: ${resp}')


def main():  # pragma: no cover
    """main function, parses params and runs command functions
    """
    params = demisto.params()
    args = demisto.args()
    command = demisto.command()
    demisto.info(f"Command called {command}")
    demisto.info(f"Args are {args}")
    demisto.info(f"params are {params}")
    client = Client(params)
    try:
        if command == 'quttera-scan-start':
            results = scan_start(client, args)
        elif command == 'quttera-rescan-status':
            results = rescan_status(client, args)
        elif command == 'quttera-scan-report':
            results = scan_report(client, args)
        elif command == 'quttera-report-malware':
            results = report_malware(client, args)
        elif command == 'quttera-status-blacklist':
            results = status_blacklist(client, args)
        elif command == 'test-module':
            results = test_module(client)
        else:
            raise ValueError(f'Command {command} is not implemented in this integration')
        return_results(results)
    except Exception as e:
        return_error(f'Failed to execute {command} command.\nError:\n{str(e)}')


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