###
# Copyright (c) 2017, Ormanya
# Copyright (c) 2020, oddluck <oddluck@riseup.net>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###

import supybot.plugins as plugins
from supybot.commands import *
import supybot.ircutils as ircutils
import supybot.callbacks as callbacks
import requests
import json
import sys
import re

import supybot.schedule as schedule
from datetime import datetime


status_commands = [
    "btnStatus",
    "redStatus",
    "mtvStatus",
    "nwcdStatus",
    "ptpStatus",
    "ggnStatus",
    "arStatus",
    "p32Status",
    "ahdStatus",
    "ahdStatus",
    "empStatus",
    "nblStatus",
]
status_trackers = [
    "btn",
    "red",
    "mtv",
    "nwcd",
    "ptp",
    "ggn",
    "ar",
    "p32",
    "ahd",
    "ahd",
    "emp",
    "nbl",
]


class WebParser:
    """Contains functions for getting and parsing web data"""

    def getWebData(self, irc, url):
        headers = {
            "User-Agent": (
                "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko)"
                " Chrome/24.0.1312.27 Safari/537.17"
            )
        }
        try:
            content = requests.get(url, headers=headers, timeout=10)
            content = json.loads(content.content)
            return content
        except:
            irc.reply("Error: Couldn't connect to " + url)
            return

    def prepareStatusString(
        self, site_name, status, status_headers, breakpoints, line_headers
    ):
        # Specify look and feel
        status_states = ["Down", "Up", "Iffy", "Mean"]
        status_symbols = ["Ⓧ", "✓", "◯", "💩"]
        status_colours = [chr(3) + "04", chr(3) + "09", chr(3) + "07", chr(3) + "13"]

        # Prepare output status message
        outStr = [line_headers[0]]
        count = 0
        line = 0
        for element in status:
            count = count + 1
            i = int(element)

            outStr[line] = (
                outStr[line]
                + status_colours[i]
                + status_symbols[i]
                + " "
                + status_headers[count - 1]
                + " "
                + status_states[i]
            )

            # Split output at breakpoints
            if count in breakpoints:
                line = line + 1
                outStr.extend([line_headers[line]])
            # don't append "|" if end of line
            elif count != len(status):
                outStr[line] = outStr[line] + chr(15) + " | "
        return outStr


class Trackers(callbacks.Plugin):
    """Contains commands for checking server status of various trackers."""

    threaded = True

    # def __init__(self, irc):
    #     print "Setting it up"

    #     self.__parent = super(Trackers, self)
    #     self.__parent.__init__(irc)
    #     # Set  scheduler variables

    #     # Schedule announce check
    #     # Check if event already exists
    #     try:
    #         schedule.removeEvent('statusAnnounce')
    #     except KeyError:
    #         pass

    #     def myEventCaller():
    #         print "Scheduling announce"
    #         self.autoAnnounce(irc)

    #     schedule.addPeriodicEvent(myEventCaller, 30, 'statusAnnounce')
    #     self.irc = irc

    #     print "All done"

    def formatTimeSince(self, interval):
        # seconds
        if (interval.days == 0) and (interval.seconds < 60):
            time_passed = "%s seconds ago" % interval.seconds
        # minutes
        elif interval.days == 0 and interval.seconds < 3600:
            if interval.seconds < 120:
                time_passed = "1 minute ago"
            else:
                time_passed = "%s minutes ago" % int(interval.seconds / 60)
        # hours
        elif interval.days == 0:
            if interval.seconds < 7200:
                time_passed = "1 hour ago"
            else:
                time_passed = "%s hours ago" % int(interval.seconds / 3600)
        # days
        elif interval.days < 7:
            if interval.days == 1:
                time_passed = "1 day ago"
            else:
                time_passed = "%s days ago" % interval.days
        # weeks
        else:
            if interval.days < 14:
                time_passed = "1 week ago"
            else:
                time_passed = "%s weeks ago" % int(interval.days / 7)

        return time_passed

    def btnStatus(self, irc, msg, args, opts):
        """[--message]

        Check the status of BTN site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "https://btn.trackerstatus.info/api/status/"
        site_name = "BTN"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["API"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["CableGuy"],
            content["Barney"],
            3,
        ]
        status_headers = [
            "Site",
            "API",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Id",
            "IRC Announce",
            "kenyz",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    btn = wrap(btnStatus, [optional("something")])

    def redStatus(self, irc, msg, args, opts):
        """[--message]

        Check the status of Redacted site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://red.trackerstatus.info/api/status/"
        site_name = "RED"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    red = wrap(redStatus, [optional("something")])

    def opsStatus(self, irc, msg, args, opts):
        """[--message]

        Check the status of Orpheus site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://ops.trackerstatus.info/api/status/"
        site_name = "OPS"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    ops = wrap(opsStatus, [optional("something")])

    def mtvStatus(self, irc, msg, args, opts):
        """
        Check the status of MTV site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://mtv.trackerstatus.info/api/status/"
        site_name = "MTV"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    mtv = wrap(mtvStatus, [optional("something")])

    def nwcdStatus(self, irc, msg, args, opts):
        """
        Check the status of NWCD site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://nwcd.trackerstatus.info/api/status/"
        site_name = "NWCD"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
            content["ImageHost"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
            "Image Host",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    nwcd = wrap(nwcdStatus, [optional("something")])

    def ptpStatus(self, irc, msg, args, opts):
        """
        Check the status of PTP site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "https://ptp.trackerstatus.info/api/status/"
        site_name = "PTP"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
            content["TrackerHTTPAddresses"]["51.255.35.90"],
            content["TrackerHTTPAddresses"]["164.132.51.73"],
            content["TrackerHTTPAddresses"]["164.132.54.181"],
            content["TrackerHTTPAddresses"]["164.132.54.182"],
            content["TrackerHTTPAddresses"]["192.99.58.220"],
            content["IRC"],
        ]
        status_headers = [
            site_name + " Site",
            "IRC Announce",
            "IRC ID",
            "51.255.35.90",
            "164.132.51.73",
            "164.132.54.181",
            "164.132.54.182",
            "192.99.58.220",
            "Persona",
        ]
        breakpoints = [3]
        line_headers = ["Services: ", "Trackers: "]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    ptp = wrap(ptpStatus, [optional("something")])

    def ggnStatus(self, irc, msg, args, opts):
        """
        Check the status of GGN site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "https://ggn.trackerstatus.info/api/status/"
        site_name = "GGn"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "TrackerSSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    ggn = wrap(ggnStatus, [optional("something")])

    def arStatus(self, irc, msg, args, opts):
        """
        Check the status of AR site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://ar.trackerstatus.info/api/status/"
        site_name = "AR"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["TrackerHTTPS"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "Tracker SSL",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    ar = wrap(arStatus, [optional("something")])

    def p32Status(self, irc, msg, args, opts):
        """
        Check the status of AR site, tracker, and irc. Use --message flag to force return of message, even if older than 24 hours.
        """
        url = "http://32p.trackerstatus.info/api/status/"
        site_name = "32p"

        content = WebParser().getWebData(irc, url)

        status = [
            content["Website"],
            content["TrackerHTTP"],
            content["IRC"],
            content["IRCTorrentAnnouncer"],
            content["IRCUserIdentifier"],
        ]
        status_headers = [
            site_name + " Site",
            "Tracker",
            "IRC",
            "IRC Announce",
            "IRC ID",
        ]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

        # Output message if --message flag specified or newer than 1 day
        interval = datetime.now() - datetime.fromtimestamp(
            float(content["tweet"]["unix"])
        )
        if opts == "--message" or interval.days < 1:
            message_string = content["tweet"]["message"]
            time_string = self.formatTimeSince(interval)

            outstr = "%s message: %s (%s)" % (site_name, message_string, time_string)
            irc.reply(outstr)

    p32 = wrap(p32Status, [optional("something")])

    def ahdStatus(self, irc, msg, args, all):
        """
        Check the status of AHD site, tracker, and irc.
        """

        # This function is different than the others because it scrapes HTML rather than use an api site
        url = "https://status.awesome-hd.me"
        site_name = "AHD"

        # Get web page content
        headers = {
            "User-Agent": (
                "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko)"
                " Chrome/24.0.1312.27 Safari/537.17"
            )
        }
        try:
            content = requests.get(url, headers=headers)
        except:
            irc.reply("Error: Couldn't connect to " + url)
            return

        # Extract statuses
        status_txt = re.search(
            r'.*Site.*2x\ (.*)".*\n.*2x\ (.*)".*\n.*2x\ (.*)"', content.content.decode()
        )
        print(status_txt)
        status = []
        for i in range(0, 4):
            if status_txt.group(i) == "green":
                status.append(1)
            else:
                status.append(0)

        status = [status[1], status[2], status[3]]
        status_headers = [site_name + " Site", "IRC", "Tracker"]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

    ahd = wrap(ahdStatus, [optional("something")])

    def abStatus(self, irc, msg, args, all):
        """
        Check the status of AB site, tracker, and irc.
        """

        # This function is different than the others because it scrapes HTML rather than use an api site
        url = "http://status.animebytes.tv"
        site_name = "AB"

        # Get web page content
        headers = {
            "User-Agent": (
                "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko)"
                " Chrome/24.0.1312.27 Safari/537.17"
            )
        }
        try:
            content = requests.get(url, headers=headers)
        except:
            irc.reply("Error: Couldn't connect to " + url)
            return

        # Extract statuses
        status_txt = re.search(
            r'.*site.*\n.*status (.*)"[\S\s]+tracker.*\n.*status'
            r' (.*)"[\S\s]+irc.*\n.*status (.*)"',
            content.content.decode(),
        )
        status = []
        for i in range(0, 4):
            if status_txt.group(i) == "normal":
                status.append(1)
            else:
                status.append(0)

        status = [status[1], status[3], status[2]]
        status_headers = [site_name + " Site", "IRC", "Tracker"]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

    ab = wrap(abStatus, [optional("something")])

    def empStatus(self, irc, msg, args, all):
        """
        Check the status of EMP site, tracker, and irc.
        """

        # This function is different than the others because it scrapes HTML rather than use an api site
        url = "http://about.empornium.ph/"
        site_name = "EMP"

        # Get web page content
        headers = {
            "User-Agent": (
                "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.17 (KHTML, like Gecko)"
                " Chrome/24.0.1312.27 Safari/537.17"
            )
        }
        try:
            content = requests.get(url, headers=headers)
        except:
            irc.reply("Error: Couldn't connect to " + url)
            return

        # Extract statuses
        status_txt = re.search(
            r'.*pull-right">(.*)<\/span>[\S\s.]+?pull-right">(.*)<\/span>[\S\s.]+?pull-right">(.*)<\/span>[\S\s.]+?pull-right">(.*)<\/span>',
            content.content.decode(),
        )
        status = []
        for i in range(0, 5):
            if status_txt.group(i) == "Online":
                status.append(1)
            else:
                status.append(0)

        status = [status[1], status[2], status[4], status[3]]
        status_headers = [site_name + " Site.me", "Site.sx", "Tracker", "IRC"]
        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

    emp = wrap(empStatus, [optional("something")])

    def nblStatus(self, irc, msg, args, all):
        """
        Check the status of Nebulance site, tracker, and irc.
        """
        url = "https://status.nebulance.io/status.json"
        site_name = "NBL"

        content = WebParser().getWebData(irc, url)
        content2 = content["services"]

        status_tmp = [
            content2["site"]["status"],
            content2["tracker"]["status"],
            content2["tracker_ssl"]["status"],
            content2["imagehost"]["status"],
        ]
        status = []
        for service in status_tmp:
            if service:
                status.append(1)
            else:
                status.append(0)
        status_headers = [site_name + " Site", "Tracker", "Tracker SSL", "Image Host"]

        breakpoints = [0]
        line_headers = [""]

        outStr = WebParser().prepareStatusString(
            site_name, status, status_headers, breakpoints, line_headers
        )

        for i in range(0, len(outStr)):
            irc.reply(outStr[i])

    nbl = wrap(nblStatus, [optional("something")])

    # def autoAnnounce(self, irc):
    #     """Schedule periodic announces for enabled trackers and channels"""
    #     print "Start"
    #     i = 0
    #     for cmd in status_commands:
    #         print cmd
    #         for channel in irc.state.channels:
    #             print "announce.relay"+status_trackers[i]
    #             if self.registryValue("announce.relay"+status_trackers[i], channel):
    #                 print "announce.relay"+status_trackers[i]
    #                 try:
    #                     locals()["self."+cmd]()
    #                 except:
    #                     print "Failed to query status"
    #                 print channel
    #         i = +1


Class = Trackers
