import requests
from core.errors import GenericYetiError
from core.analytics import OneShotAnalytics
from core.observables import Hash, Hostname, Url
from core.config.config import yeti_config


class MalwaresApi(object):
    """
        https://www.malwares.com/about/api
    """

    settings = {
        "malwares_api_key": {
            "name": "Malwares API Key",
            "description": "API Key provided by malwares.com."
        }
    }

    API_URL = "https://public.api.malwares.com/v3/"

    @staticmethod
    def _process_data(json_result, observable):
        links = set()

        for key in ("undetected_communicating_file",
                    "detected_downloaded_file",
                    "undetected_downloaded_file",
                    "detected_communicating_file"):
            for file_hash in json_result.get(key, []):
                new_hash = Hash.get_or_create(value=file_hash)
                new_hash.tag(observable.get_tags())
                links.update(
                    new_hash.active_link_to(observable,
                        key, "malwares.com")
                )

        for host in json_result.get("hostname_history", {}).get("list", []):
            new_host = Hostname.get_or_create(value=host)
            new_host.tag(observable.get_tags())
            links.update(
                new_host.active_link_to(observable,
                    "hostname", "malwares.com")
                )

        for key in ("detected_url", "undetected_url", "distribution_url"):
            for url in json_result.get(key, []):
                new_url = Url.get_or_create(value=url)
                new_url.tag(observable.get_tags())
                links.update(
                    new_url.active_link_to(observable,
                        key, "malwares.com")
                )

        observable.add_context(json_result)
        return list(links)

    @staticmethod
    def fetch(observable, params, uri):
        try:
            url = MalwaresApi.API_URL + uri
            response = requests.get(
                url, params=params, proxies=yeti_config.proxy)
            if not response.ok:
                raise GenericYetiError("Status code: ".format(response.status_code))
            return response.json()
        except Exception as e:
            raise GenericYetiError("Hit an error checking {},{}".format(
                observable.value, e
            ))

class IpReport(OneShotAnalytics, MalwaresApi):
    """
        https://www.malwares.com/about/api#IPInfo
    """
    default_values = {
        "group": "Malwares",
        "name": "Malwares Ip Report",
        "description": "Perform a IP lookup."
    }

    ACTS_ON = ["Ip"]

    @staticmethod
    def analyze(observable, results):
        params = {
            "api_key": results.settings["malwares_api_key"],
            "ip": observable.value,
            "host": "1",
            "url": "1",
            "downfile": "1",
            "comfile": "3"
        }

        json_result = MalwaresApi.fetch(
            observable, params, "ip/info")

        links = MalwaresApi._process_data(json_result, observable)
        return links

class HostnameReport(OneShotAnalytics, MalwaresApi):
    """
        https://www.malwares.com/about/api#IPInfo
    """

    default_values = {
        "group": "Malwares",
        "name": "Hostname Report",
        "description": "Perform a Hostname lookup."
    }

    ACTS_ON = ["Hostname"]

    @staticmethod
    def analyze(observable, results):
        links = set()
        params = {
            "api_key": results.settings["malwares_api_key"],
            "hostname": observable.value,
            "ip": 1,
            "url": 1,
            "downfile": 1,
            "comfile": 3
        }

        json_result = MalwaresApi.fetch(
            observable, params, "hostname/info")

        links = MalwaresApi._process_data(json_result, observable)
        return links


class HashReport(OneShotAnalytics, MalwaresApi):
    """
        https://www.malwares.com/about/api#AddInfo
    """
    default_values = {
        "group": "Malwares",
        "name": "Hash Report",
        "description": "Perform a Hash lookup."
    }

    ACTS_ON = ["Hash"]

    @staticmethod
    def analyze(observable, results):

        params = {
            "api_key": results.settings["malwares_api_key"],
            "hash": observable.value,
        }

        json_result = MalwaresApi.fetch(
            observable, params, "file/addinfo")

        links = MalwaresApi._process_data(json_result, observable)
        return links
