import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
from typing import Tuple


''' IMPORTS '''

import dateparser
import requests
import trustar
import urllib3
from trustar.models.indicator import Indicator
from trustar.models.report import Report

# Disable insecure warnings
urllib3.disable_warnings()

handle_proxy()


class Utils(object):
    """
    Class with some utility methods.
    """
    @staticmethod
    def normalize_time(timestamp):
        ''' Converts unix epoch time to GMT '''
        if isinstance(timestamp, str):
            return timestamp
        return time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(timestamp / 1000.0))

    @staticmethod
    def date_to_unix(timestamp):
        d = dateparser.parse(timestamp)
        assert d is not None, f'could not parse {timestamp}'
        return int(d.strftime("%s")) * 1000


class ContextManager(object):
    """
    Manages where to put the data depending if the data to output is an indicator or not.

    If data is an indicator, the data is returned on 3 contexts:
    - DBotScore context: Contains the value of the IOC, the vendor (TruSTAR) and a score of 0.
    - Standard context: Groups all IOCs by types and returns the value of each one.
    - TruSTAR context: Contains all the information fetched from TruSTAR corresponding to each indicator.
    Data is also returned on the TruSTAR context for phishing submissions and reports.
    """

    INDICATOR_TYPES = {
        'URL': Common.URL,
        'IP': Common.IP,
        'DOMAIN': Common.Domain,
        'CVE': Common.CVE
    }

    DBOTSCORE_TYPES = {
        'URL': DBotScoreType.URL,
        'IP': DBotScoreType.IP,
        'DOMAIN': DBotScoreType.DOMAIN,
        'CVE': DBotScoreType.CVE,
        'SOFTWARE': DBotScoreType.FILE,
        'SHA256': DBotScoreType.FILE,
        'SHA1': DBotScoreType.FILE,
        'MD5': DBotScoreType.FILE,
    }

    FILE_TYPES = ['SOFTWARE', 'SHA256', 'SHA1', 'MD5']

    def _get_dbot_score(self, ts_indicator):
        """ Returns a DBotScore object with score as None """
        indicator_type = ts_indicator.get('indicatorType')
        dbot_score = Common.DBotScore(
            indicator=ts_indicator.get('value'),
            indicator_type=self.DBOTSCORE_TYPES.get(indicator_type),
            integration_name='TruSTAR',
            score=Common.DBotScore.NONE
        )
        return dbot_score

    def _get_xsoar_file_indicator(self, ts_indicator, dbot_score):
        """
        Returns a Common.File object. Handles logic to create the object with
        the corresponding type (SHA1, SHA256, MD5 or Name if software).
        """

        key = ts_indicator.get('indicatorType')
        key = "name" if key == "SOFTWARE" else key
        value = ts_indicator.get('value')
        args = {
            key.lower(): value,
            'dbot_score': dbot_score
        }
        xsoar_file_indicator = Common.File(**{k: v for k, v in args.items() if k})
        return xsoar_file_indicator

    def _get_xsoar_indicator_and_readable_output(self, ts_indicator) -> Tuple[Common.Indicator, str]:
        """
        Returns a XSoar Indicator with DBotScore embedded and their human readable. Indicators can be:
        - Common.File
        - Common.IP
        - Common.URL
        - Common.CVE
        """

        indicator_type = ts_indicator.get('indicatorType')
        if indicator_type == "CVE":
            return (Common.CVE(ts_indicator.get('value'), None, None, None, None),
                    f'Fetched CVE {ts_indicator.get("value")} details')

        dbot_score = self._get_dbot_score(ts_indicator)
        if indicator_type in self.FILE_TYPES:
            return (self._get_xsoar_file_indicator(ts_indicator, dbot_score),
                    f'Fetched File {ts_indicator.get("value")} details')

        XSOARIndicator = self.INDICATOR_TYPES.get(indicator_type)
        xsoar_indicator = XSOARIndicator(
            ts_indicator.get('value'),
            dbot_score=dbot_score
        ) if XSOARIndicator is not None else None
        return xsoar_indicator, f'Fetched {indicator_type} {ts_indicator.get("value")} details'

    def _remove_priority_level(self, indicator_dict):
        """  Removes priority level from indicator. It is a deprecated field """
        if indicator_dict.get('priorityLevel'):
            indicator_dict.pop('priorityLevel')

        return indicator_dict

    def get_context(self, indicators, context='Indicator'):
        """
        Handles logic to return an entry context with xsoar and non xsoar indicators
        on their corresponding contexts.
        """
        context_results: List[dict] = []
        indicators = [self.convert_indicator_timestamps(d) for d in indicators]
        indicators = [self._remove_priority_level(d) for d in indicators]
        xsoar_indicators = [
            self._get_xsoar_indicator_and_readable_output(d)
            for d in indicators
            if d.get('indicatorType') not in {'EMAIL_ADDRESS', 'REGISTRY_KEY', 'MALWARE', 'CIDR_BLOCK'}
        ]
        for xsoar_ioc, hr in xsoar_indicators:
            context_results.append(CommandResults(
                indicator=xsoar_ioc,
                readable_output=hr
            ).to_context())

        standard_context = self.get_non_xsoar_standard_context(indicators)
        results = CommandResults(
            outputs_prefix=f'TruSTAR.{context}',
            outputs_key_field='value',
            outputs=indicators,
        )
        context = results.to_context()
        context['EntryContext'].update(standard_context)

        # insert the TruStar result as the first item in results
        context_results.insert(0, context)
        return context_results

    def convert_indicator_timestamps(self, indicator):
        """ Converts indicator timestamp fields. """
        d = {
            t: Utils.normalize_time(indicator.get(t))
            for t in ['firstSeen', 'lastSeen']
            if t in indicator.keys()
        }
        indicator.update(d)
        return indicator

    def get_indicators_context(self, indicators, context='Indicators'):
        ts_indicator_dicts = [
            i.to_dict(remove_nones=True)
            for i in indicators
        ]

        return self.get_context(ts_indicator_dicts, context)

    def get_indicator_summaries_context(self, indicators, context='Indicators'):
        ts_indicator_dicts = [
            i.to_dict(remove_nones=True)
            for i in indicators
        ]

        for d in ts_indicator_dicts:
            d['indicatorType'] = d.pop('type')  # Adding IndicatorType field

        return self.get_context(ts_indicator_dicts, context)

    def get_non_xsoar_standard_context(self, indicator_dicts):
        """
        Returns a standard context for those indicator types that can not be automated
        with one of the 'Common' classes. Depending on the type of indicator,
        the data is put on the corresponding context.
        """
        emails = [
            {'Address': i.get('value')}
            for i in indicator_dicts
            if i.get('indicatorType') == "EMAIL_ADDRESS"
        ]

        registries = [
            {'Path': i.get('value')}
            for i in indicator_dicts
            if i.get('indicatorType') == "REGISTRY_KEY"
        ]
        standard_ec = {}
        if emails:
            standard_ec['Account.Email(val.Address && val.Address === obj.Address)'] = emails
        if registries:
            standard_ec['RegistryKey(val.Path && val.Path === obj.Path)'] = registries

        return standard_ec

    def translate_triage_submission(self, submissions):
        """ Returns Entry Contex for Phishing Submissions """
        submission_dicts = [s.to_dict(remove_nones=True) for s in submissions]
        ec = {'TruSTAR.PhishingSubmission(val.submissionId == obj.submissionId)': submission_dicts}
        return submission_dicts, ec

    def get_enclaves_ec(self, enclaves):

        context = [enclave.to_dict(remove_nones=True) for enclave in enclaves]
        ec = {
            'TruSTAR.Enclave(val.id && val.id === obj.id)': context
        }
        return context, ec

    def _get_report_context_fields(self, report):
        context_fields = ["id", "title", "reportBody"]
        fields = {k: v for k, v in report.items() if k in context_fields}
        return fields

    def get_reports_ec(self, reports):
        """ Returns entry context for Reports """
        context = [self._get_report_context_fields(report) for report in reports]
        ec = {
            'TruSTAR.Report(val.id && val.id === obj.id)': context
        }
        return ec

# ## CLIENT ###


class TrustarClient:
    """
    Class wrapper of TruSTAR SDK.

    Interpretates a command and retrieves the correspondding data
    from TruSTAR to be shown on the war room and put on the corresponding
    context.
    """

    LIST_ARGS = [
        "indicators",
        "indicator_types",
        "values",
        "enclave_ids",
        "priority_event_score",
        "normalized_indicator_score",
        "status",
        "tags",
        "exclueded_tags"
    ]

    def __init__(self, config, station=''):
        self.client = trustar.TruStar(config=config)
        self.command_dict = self._build_command_dict()
        self.context_manager = ContextManager()
        self.station = station

    def _build_command_dict(self):
        command_dict = {
            'test-module': self.test_module,
            'trustar-get-reports': self.get_reports,
            'trustar-get-enclaves': self.get_enclaves,
            'trustar-related-indicators': self.get_related_indicators,
            'trustar-indicators-metadata': self.get_indicators_metadata,
            'trustar-indicator-summaries': self.get_indicator_summaries,
            'trustar-get-whitelisted-indicators': self.get_whitelist,
            'trustar-move-report': self.move_report,
            'trustar-trending-indicators': self.get_trending_indicators,
            'trustar-get-indicators-for-report': self.get_indicators_for_report,
            'trustar-search-indicators': self.search_indicators,
            'trustar-submit-report': self.submit_report,
            'trustar-delete-report': self.delete_report,
            'trustar-correlated-reports': self.get_correlated_reports,
            'trustar-add-to-whitelist': self.add_to_whitelist,
            'trustar-remove-from-whitelist': self.remove_from_whitelist,
            'trustar-report-details': self.get_report_details,
            'trustar-update-report': self.update_report,
            'trustar-search-reports': self.search_reports,
            'trustar-get-phishing-indicators': self.get_all_phishing_indicators,
            'trustar-get-phishing-submissions': self.get_phishing_submissions,
            'trustar-set-triage-status': self.set_triage_status,
            'trustar-copy-report': self.copy_report
        }
        return command_dict

    def get_entry(self, title='', contents=None, ec=None):
        """
        Returns Context dictionary
        """
        entry = {
            'Type': EntryType.NOTE,
            'Contents': contents,
            'ContentsFormat': EntryFormat.JSON,
            'ReadableContentsFormat': EntryFormat.MARKDOWN,
            'HumanReadable': tableToMarkdown(title, contents),
        }
        if ec:
            entry['EntryContext'] = ec

        return entry

    def get_report_timestamps(self, report):
        """ Given a report dictionary, it returns the timestamp fields
        on a dictionary.
        """
        d = {
            t: Utils.normalize_time(report[t])
            for t in ['updated', 'created', 'timeBegan']
            if report.get(t)
        }
        return d

    def get_report_deep_link(self, report_id):
        """ Returns report link on TruSTAR self.station. """
        return f'{self.station}/constellation/reports/{report_id}'

    def test_module(self):
        """Tests connectivity with TruSTAR"""
        try:
            self.client.ping()
            return "ok"
        except requests.exceptions.HTTPError:
            return ("Invalid Credentials. Please check your API Key and Secret"
                    "are correct on TruSTAR Station. Settings > API")

    def search_indicators(self,
                          search_term=None,
                          enclave_ids=None,
                          from_time=None,
                          to_time=None,
                          indicator_types=None,
                          tags=None,
                          excluded_tags=None,
                          limit=None):
        """
        Searches for all indicators that contain the given search term.

        :param search_term: Term to be searched.
        :param enclave_ids: list of enclaves to restrict the search to.
        "param limit: Max number of entries to be returned.

        :return: Entry context with found indicators.
        """
        """
        Searches for all indicators that contain the given search term.

        :param search_term: Term to be searched.
        :param enclave_ids: list of enclaves to restrict the search to.
        "param limit: Max number of entries to be returned.

        :return: Entry context with found indicators.
        """
        from_time = Utils.date_to_unix(from_time) if from_time else from_time
        to_time = Utils.date_to_unix(to_time) if to_time else to_time
        try:
            response = self.client.search_indicators_page(
                search_term=search_term,
                enclave_ids=enclave_ids,
                from_time=from_time,
                to_time=to_time,
                tags=tags,
                indicator_types=indicator_types,
                excluded_tags=excluded_tags,
                page_number=0,
                page_size=limit,
            )

            if not response:
                return 'No indicators were found.'

        except requests.exceptions.HTTPError as err:
            if err.response.status_code == 400:
                return 'No indicators were found.'

            raise(err)

        results = self.context_manager.get_indicators_context(response)
        return results

    def get_reports(self,
                    from_time=None,
                    to_time=None,
                    enclave_ids=None,
                    distribution_type=None,
                    tags=None,
                    excluded_tags=None):
        """
        Returns incident reports matching the specified filters.

        :param from_time: Start of polling window.
        :param to_time: End of polling window.
        :param enclave_ids: List of user enclaves to restrict the query.
        :param distribution_type: Whether to search for reports in the community, or only
        in enclaves.
        :param tags: a list of names of tags to filter by.
        :param excluded_tags: reports containing ANY of these tags will be excluded from the
        results.

        :return: Entry context with found reports.
        """
        is_enclave = (distribution_type == 'ENCLAVE')
        from_time = Utils.date_to_unix(from_time) if from_time else from_time
        to_time = Utils.date_to_unix(to_time) if to_time else to_time
        response = self.client.get_reports_page(
            is_enclave,
            enclave_ids,
            tags,
            excluded_tags,
            from_time,
            to_time
        )

        if not response:
            return 'No reports were found.'

        reports = []
        for report in response.items:
            current_report = report.to_dict(remove_nones=True)
            current_report['reportDeepLink'] = self.get_report_deep_link(current_report.get("id"))
            current_report.update(self.get_report_timestamps(current_report))
            reports.append(current_report)

        ec = self.context_manager.get_reports_ec(reports)
        title = 'TruSTAR reports'
        entry = self.get_entry(title, reports, ec)
        return entry

    def submit_report(self,
                      title=None,
                      report_body=None,
                      enclave_ids=None,
                      external_url=None,
                      time_began=None,
                      distribution_type="ENCLAVE",
                      redact="NO"):
        """
        Submits a new report to TruSTAR station.

        :param title: Title of the report.
        :param report_body: Body of the report.
        :param enclave_ids: Enclave IDs where to submit the report.
        :param external_url: External URL of the report.
        :param time_began: Incident time. Defaults to current time if not given.
        :param distribution_type: Whether the report will be in the community, or only
        in enclaves
        :param redact: Wether to redact a report before submitting or not.

        :return: Entry context with the submitted report.
        """
        if distribution_type == 'ENCLAVE' and enclave_ids is None:
            raise Exception('Distribution type is ENCLAVE, but no enclave ID was given.')

        if redact == "YES":
            response = self.client.redact_report(
                title=title,
                report_body=report_body
            )

            title = response.title
            report_body = response.body

        ts_report = trustar.models.Report(
            title=title,
            body=report_body,
            enclave_ids=enclave_ids,
            is_enclave=(distribution_type == 'ENCLAVE'),
            time_began=time_began,
            external_url=external_url
        )

        response = self.client.submit_report(ts_report)
        report = ts_report.to_dict(remove_nones=True)
        report['reportDeepLink'] = self.get_report_deep_link(response.id)
        report['id'] = response.id
        ec = self.context_manager.get_reports_ec([report])
        title = 'TruSTAR report was successfully created'
        entry = self.get_entry(title, report, ec)
        return entry

    def delete_report(self, report_id=None, id_type=None):
        """
        Deletes report from TruStar.

        :param report_id: ID of the report to be deleted.
        :param id_type: Report id type. External or internal.

        :return: Success Message.
        """
        self.client.delete_report(report_id, id_type)
        return f'Report {report_id} was successfully deleted'

    def get_correlated_reports(self,
                               indicators=None,
                               enclave_ids=None,
                               distribution_type=None,
                               limit=None):
        """
        Returns a list of all reports that contain any of the provided
        indicator values.

        :param indicators: indicators list to perform the query.
        :param enclave_ids: enclaves list to restrict the query.
        :param distribution_type: Distribution type of the report.
        :param limit: Maximum value of report to be returned.

        :return: Entry context with found reports.
        """
        response = self.client.get_correlated_reports_page(
            indicators,
            enclave_ids,
            is_enclave=(distribution_type == "ENCLAVE"),
            page_number=0,
            page_size=limit
        )

        if not response:
            return 'No reports were found.'

        correlated_reports = []
        for report in response:
            current_report = report.to_dict(remove_nones=True)
            current_report.update(self.get_report_timestamps(current_report))
            correlated_reports.append(current_report)

        title = 'TruSTAR correlated reports'
        entry = self.get_entry(title, correlated_reports)
        return entry

    def get_report_details(self, report_id=None, id_type=None):
        """
        Finds a report by its ID and returns the report details.

        :param report_id: Report ID.
        :param id_type: Type of report ID. External or internal.

        :return: Entry context with Report queried.
        """
        response = self.client.get_report_details(report_id, id_type)
        if not response:
            return f"No details were found for report ID {report_id}"

        current_report_dict = response.to_dict(remove_nones=True)
        id = current_report_dict.get("id")
        current_report_dict.update(self.get_report_timestamps(current_report_dict))
        current_report_dict['reportDeepLink'] = self.get_report_deep_link(id)

        ec = self.context_manager.get_reports_ec([current_report_dict])

        title = f'TruSTAR report ID {report_id} details'
        entry = self.get_entry(title, current_report_dict, ec)
        return entry

    def update_report(self, **kwargs):
        """
        Update the report with the specified ID. Either the internal TruSTAR
        report ID or an external tracking ID can be used. Only the fields passed will
        be updated. All other fiels will remain unchanged.

        :return: Entry Context with updated report.
        """
        report_id = kwargs.pop('report_id')
        ts_report = self.client.get_report_details(report_id).to_dict()

        if kwargs.get('distribution_type'):
            kwargs["distributionType"] = kwargs.pop('distribution_type')

        if kwargs.get('report_body'):
            kwargs["reportBody"] = kwargs.pop('report_body')

        if kwargs.get('enclave_ids'):
            kwargs["enclaveIds"] = kwargs.pop('enclave_ids')

        if kwargs.get('external_url'):
            kwargs["externalUrl"] = kwargs.pop('external_url')

        if kwargs.get('time_began'):
            kwargs["timeBegan"] = kwargs.pop('time_began')

        ts_report.update(kwargs)
        self.client.update_report(Report.from_dict(ts_report))

        ts_report.update(self.get_report_timestamps(ts_report))
        ts_report['reportDeepLink'] = self.get_report_deep_link(report_id)
        ec = self.context_manager.get_reports_ec([ts_report])

        title = 'TruSTAR report was successfully updated'
        entry = self.get_entry(title, ts_report, ec)
        return entry

    def get_enclaves(self):
        """
        Returns the list of all enclaves that the user has access to, as
        well as whether they can read, create, and update reports in that enclave.

        :return: Entry context with list of enclaves
        """
        response = self.client.get_user_enclaves()
        enclaves, ec = self.context_manager.get_enclaves_ec(response)

        if not response:
            return "No enclaves were found."

        title = 'TruSTAR Enclaves'
        entry = self.get_entry(title, enclaves, ec)
        return entry

    def get_related_indicators(self, indicators=None, enclave_ids=None, limit=None):
        """
        Finds all reports that contain any of the given indicators
        and returns correlated indicators from those reports.

        :param indicators: list of indicator values.
        :param enclave_ids: list of enclaves to filter found reports.
        :param limit: Max num of related indicators to return.

        :return: Entry Context with related indicators.
        """
        related_indicator_response = self.client.get_related_indicators_page(
            indicators=indicators,
            enclave_ids=enclave_ids,
            page_size=limit,
            page_number=0
        )

        if not related_indicator_response:
            return f'No indicators related to {indicators} were found.'

        results = self.context_manager.get_indicators_context(related_indicator_response.items)
        return results

    def get_trending_indicators(self, indicator_type=None, days_back=None):
        """
        Find indicators that are trending in the community.

        :param indicator_type: Types of indicators to be returned. If is equal to 'other',
        then all indicator types except for CVE and MALWARE will be returned.
        :param days_back: The number of days back to count correlations for.

        """
        indicator_type = None if indicator_type == 'other' else indicator_type
        response = self.client.get_community_trends(indicator_type, days_back)

        if not response:
            return 'No trending indicators were found.'

        results = self.context_manager.get_indicators_context(response)
        return results

    def search_reports(self,
                       search_term=None,
                       enclave_ids=None,
                       from_time=None,
                       to_time=None,
                       tags=None,
                       excluded_tags=None,
                       limit=None):
        """
        Searches for all reports that contain the given search term.

        :param search_term: term to search for within the reports.
        :param enclave_ids: list of enclaves to restrict te search to.

        :return: Entry Context with Found reports.
        """
        from_time = Utils.date_to_unix(from_time) if from_time else from_time
        to_time = Utils.date_to_unix(to_time) if to_time else to_time
        response = self.client.search_reports_page(
            search_term=search_term,
            enclave_ids=enclave_ids,
            from_time=from_time,
            to_time=to_time,
            tags=tags,
            excluded_tags=excluded_tags,
            page_number=0,
            page_size=limit
        )
        if not response:
            return "No reports were found"

        reports = []
        for report in response:
            current_report = report.to_dict(remove_nones=True)
            current_report.update(self.get_report_timestamps(current_report))
            reports.append(current_report)

        ec = self.context_manager.get_reports_ec(reports)

        title = f'TruSTAR reports that contain the term {search_term}'
        entry = self.get_entry(title, reports, ec)
        return entry

    def add_to_whitelist(self, indicators=None):
        """
        Adds a list of indicators to the Company's whitelist.

        :param indicators: list of indicators to be whitelisted.

        :return: Message indicating if the request was successful or not.
        """
        response = self.client.add_terms_to_whitelist(indicators)
        if not response:
            return 'Indicator could not be added to the whitelist.'

        return f'{indicators} added to the whitelist successfully'

    def remove_from_whitelist(self, indicator=None, indicator_type=None):
        """
        Deletes an indicator from the Company's whitelist.

        :param indicator: Indicator to be deleted.
        :param indicator_type: type of the indicator to be deleted.

        :return: Message with the result of the request.
        """
        ts_indicator = Indicator(
            value=indicator,
            type=indicator_type
        )
        try:
            self.client.delete_indicator_from_whitelist(ts_indicator)
            return f'{indicator} removed from the whitelist successfully'
        except Exception:
            return 'Indicator could not be removed from the whitelist.'

    def get_indicators_metadata(self, indicators=None, enclave_ids=None):
        """
        Provide metadata associated with a list of indicators. The metadata is determined based on the
        enclaves the user making the request has READ access to.

        :param indicators: indicators list to search the corresponding metadata.
        :param enclave_ids: list of enclave IDs to restrict to. By default, uses all of the user’s enclaves.

        :return: Entry context with indicators metadata.
        """

        ts_indicators = [Indicator(value=i) for i in indicators]
        response = self.client.get_indicators_metadata(ts_indicators, enclave_ids)

        if not response:
            return 'No indicators metadata were found.'

        results = self.context_manager.get_indicators_context(response, "IndicatorsMetadata")
        return results

    def get_indicator_summaries(self, values=None, enclave_ids=None, limit=None):
        """
        Provides structured summaries about indicators, which are derived from
        intelligence sources on the TruSTAR Marketplace.

        :param values: list of indicator values to search on TruSTAR.
        :param enclave_ids: list of enclave_ids to restrict the query.
        :param limit: Maximum value of entries to return.

        :return: Entry Context with indicator summaries.
        """
        response = self.client.get_indicator_summaries_page(
            values,
            enclave_ids=enclave_ids,
            page_number=0,
            page_size=limit
        )

        if not response:
            return 'No indicator summaries were found.'

        results = self.context_manager.get_indicator_summaries_context(response.items, "IndicatorSummaries")
        return results

    def move_report(self, report_id=None, dest_enclave_id=None):
        """
        Moves report from one user enclave to another.

        :param report_id: Report ID.
        :dest_enclave_id: Enclave ID where the report will be moved.

        :return: Success Message.
        """
        response = self.client.move_report(report_id=report_id, dest_enclave_id=dest_enclave_id)
        return f"{response} has been moved to enclave id: {dest_enclave_id}"

    def copy_report(self, report_id=None, dest_enclave_id=None):
        """
        Copies report from one user enclave to another.

        :param report_id: Report ID.
        :dest_enclave_id: Enclave ID where the report will be moved.

        :return: Success Message.
        """

        response = self.client.copy_report(src_report_id=report_id, dest_enclave_id=dest_enclave_id)
        return f"{report_id} has been copied to enclave id: {dest_enclave_id} with id: {response}"

    def get_whitelist(self, limit=None):
        """
        Gets a list of indicators that the user’s company has whitelisted.

        :param limit: Maximum number of whitelisted indicators to return.
        :return: Entry context with whitelisted indicators.
        """

        response = self.client.get_whitelist_page(page_number=0, page_size=limit)
        if not response:
            return 'No Whitelist was found.'

        results = self.context_manager.get_indicators_context(response.items, 'WhitelistedIndicators')
        return results

    def get_indicators_for_report(self, report_id=None, limit=None):
        """
        Return a list of indicators extracted from a report.

        :param report_id: Report ID to extract indicators from.
        :param limit: Max number of indicators to return.

        :return: Entry context with extracted indicators.
        """

        response = self.client.get_indicators_for_report_page(
            report_id=report_id,
            page_number=0,
            page_size=limit
        )

        if not response:
            return f'No Indicators were found in report {report_id}.'

        results = self.context_manager.get_indicators_context(response.items)
        return results

    def get_all_phishing_indicators(self,
                                    priority_event_score=None,
                                    normalized_indicator_score=None,
                                    from_time=None,
                                    to_time=None,
                                    status=None,
                                    limit=None):
        """
        Get phishing indicators that match the given criteria.

        :param priority_event_score: A list with the scores to restrict the search to.
        :param normalized_indicator_score: A list with the scores to restrict the search to.
        :param from_time: Start of the polling window.
        :param to_time: End of the polling window.
        :param status: Status of the phishing indicatror.
        :param limit: Limit of results to return. Default is 25.

        :return: Entry Context with Phishing Indicators found.
        """
        args = {'priority_event_score': priority_event_score,
                'normalized_indicator_score': normalized_indicator_score,
                'status': status,
                'page_size': limit,
                'from_time': Utils.date_to_unix(from_time) if from_time else None,
                'to_time': Utils.date_to_unix(to_time) if to_time else None}
        response = self.client.get_phishing_indicators_page(**args)  # pylint: disable=E1123
        if not response:
            return 'No phishing indicators were found.'

        results = self.context_manager.get_indicators_context(response.items, 'PhishingIndicator')
        return results

    def get_phishing_submissions(self,
                                 priority_event_score=None,
                                 from_time=None,
                                 to_time=None,
                                 status=None,
                                 limit=None):
        """
        Fetches all phishing submissions that fit the given criteria.

        :param priority_event_score: List of scores to restrict the search to.
        :param from_time: Start of polling window.
        :param to_time: End of polling window.
        :param status: List of phishing submission status to restrict the search to.
        :param limit: Limit of results to return. Default is 25.

        :return: Entry Context with all phishing submissions found.
        """
        args = {'priority_event_score': priority_event_score,
                'status': status,
                'page_size': limit,
                'from_time': Utils.date_to_unix(from_time) if from_time else None,
                'to_time': Utils.date_to_unix(to_time) if to_time else None}
        response = self.client.get_phishing_submissions_page(**args)  # pylint: disable=E1123
        if not response.items:
            return 'No phishing submissions were found.'

        submissions, ec = self.context_manager.translate_triage_submission(response.items)
        title = 'TruSTAR phishing triage submissions'
        entry = self.get_entry(title, submissions, ec)
        return entry

    def set_triage_status(self, submission_id=None, status=None):
        """
        Marks a phishing email submission with one of the phishing namespace.

        :param submission_id: Phishing Submission ID.
        :param status: Submission status.

        :return: Request status message.
        """
        try:
            response = self.client.mark_triage_status(submission_id, status)
            response.raise_for_status()
            return f'Submission ID {submission_id} is {status}'
        except requests.exceptions.HTTPError as err:
            return str(err)

    def process(self, command, **kwargs):
        """
        Processes the command that the user has selected. Retrieves the params and converts
        them to the methods params syntax. Then makes the call to the helper method of the
        corresponding command and return the results. It puts data on the corresponding context and
        it also shows the data on the War room.
        """
        func = self.command_dict.get(command)
        args = {k.replace("-", "_"): v for k, v in kwargs.items()}
        list_args = {k: argToList(v) for k, v in args.items() if k in self.LIST_ARGS}
        args.update(list_args)
        result = func(**args)
        return return_results(result)


def main():
    """ PARSE AND VALIDATE INTEGRATION PARAMS """

    server = demisto.params().get('server')
    station = demisto.params().get('station')
    api_key = str(demisto.params().get('key'))
    api_secret = str(demisto.params().get('secret'))
    base_url = server + '/api/1.3' if server else None
    insecure = not demisto.params().get('insecure', False)

    LOG(f'command is {demisto.command()}')

    config = {
        'user_api_key': api_key,
        'user_api_secret': api_secret,
        'api_endpoint': base_url,
        'verify': insecure,
        'client_type': "Python_SDK",
        'client_metatag': "demisto-xsoar"
    }

    try:
        client = TrustarClient(config, station)
        client.process(demisto.command(), **demisto.args())

    except requests.exceptions.HTTPError as e:
        if e.response.status_code == 401:
            return_error("Invalid Credentials. Please check your API Key and "
                         "Secret are correct on TruSTAR Station. Settings > API")

        return_error(f'Failed to execute {demisto.command()} command. Error: {str(e)}')

    except Exception as e:
        return_error(f'Failed to execute {demisto.command()} command. Error: {str(e)}')


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