from enum import Enum

import dns.resolver
import dns.reversename
import pygeoip


class AlertType(Enum):
    BOTNET = "botnet"
    CANDC = "c&c"
    EXFIL = "exfiltration"
    DDOS = "ddos"


class Alert:
    alertID = 0

    def __init__(self, addr, type, gi, gi2):
        """Alert

        Args:
            timestamp           (datetime)      : estimated time of the beginning
            addr                (str)           : IP address
            port                (int)           : destination port
            type                (Type or str)   : type of attack detected
            proto               (str)           : transport protocol
        """
        self.id = Alert.alertID
        Alert.alertID += 1
        self.gi, self.gi2 = gi, gi2
        self.addr = addr
        self.type = type if isinstance(type, AlertType) else AlertType(type)

    def resolveLocation(self):
        try:
            cc = self.gi.country_code_by_addr(self.addr)
            org = self.gi2.org_by_addr(self.addr)
            self.location = (cc, org)
        except Exception as e:
            self.location = "unknown"
        return self.location

    def resolveDNSName(self):
        try:
            name = dns.reversename.from_address(self.addr)
            self.nameservers = dns.resolver.resolve(name, "PTR")
        except Exception as e:
            self.nameservers = "Unknown"
        return self.nameservers

    def markdownCard(self):
        self.resolveLocation()
        self.resolveDNSName()
        return f"""
### Alert - nº {self.id}

Traffic generated by a possible **{self.type.value}**.

#### Details

| IP Address | Origin | DNS name |
| - | - | - |
| {self.addr} | {self.location if self.location[1] != None else "Unknown"} | {self.nameservers} |

child
"""


class ExfiltrationAlert(Alert):
    def __init__(self, down_byte, up_byte, percentage, **kw):
        self.down_byte = down_byte
        self.up_byte = up_byte
        self.percentage = percentage
        super(ExfiltrationAlert, self).__init__(type=AlertType.EXFIL, **kw)

    def markdownCard(self):
        parentText = Alert.markdownCard(self)

        childText = f"""Flow shows a ratio of downloaded bytes over uploaded bytes above the **{self.percentage} percentile** for downloads over uploads in this session.

| Downloaded bytes | Uploaded bytes |
| - | - |
| {self.down_byte} | {self.up_byte} |
"""

        return parentText.replace("child", childText)


class DDoSAlert(Alert):
    # NOT IMPLEMENTED

    def __init__(self, frequency, duration, **kw):
        self.frequency = frequency
        self.duration = duration
        super(DDoSAlert, self).__init__(type=AlertType.DDOS, **kw)

    def markdownCard(self):
        parentText = Alert.markdownCard(self)

        childText = f"""

| Frequency | Duration |
| - | - |
"""

        return parentText.replace("child", childText)


class BotnetAlert(Alert):
    def __init__(self, subnet, peers, frequency, **kw):
        self.subnet = subnet
        self.peers = peers
        self.frequency = frequency
        super(BotnetAlert, self).__init__(type=AlertType.BOTNET, **kw)

    def markdownCard(self):
        parentText = Alert.markdownCard(self)

        childText = f"""Flows between internal host to common destinations in the same subnet, may indicate the existance of a internal botnet.

| Subnet | Rate of communications (per second) | Number of peers in the network |
| - | - | - |
| {self.subnet} | {round(self.frequency, 4)} | {len(self.peers)} |
"""

        return parentText.replace("child", childText)
