###
# Copyright (c) 2018, cottongin
# 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 pendulum
import requests
import collections
import json
from supybot import utils, plugins, ircutils, callbacks, conf, schedule, ircmsgs
from supybot.commands import *

try:
    from supybot.i18n import PluginInternationalization

    _ = PluginInternationalization("CBB")
except ImportError:
    # Placeholder that allows to run the plugin on a bot
    # without the i18n module
    _ = lambda x: x

SCOREBOARD = (
    "http://site.api.espn.com/apis/site/v2/sports/basketball/"
    "mens-college-basketball/scoreboard?lang=en&region=us"
    "&calendartype=blacklist&limit=300&groups=50&dates={date}"
)


class CBB(callbacks.Plugin):
    """Fetches College Basketball scores"""

    threaded = True

    def __init__(self, irc):
        self.__parent = super(CBB, self)
        self.__parent.__init__(irc)

    ####################
    # PUBLIC FUNCTIONS #
    ####################

    @wrap([getopts({"date": "somethingWithoutSpaces", "all": ""}), optional("text")])
    def cbb(self, irc, msg, args, options, team=None):
        """[--date] [--all] [team]
        Fetches college basketball scores/schedule for given date and/or team.
        Defaults to today and top 25 teams (if playing, otherwise shows all games).
        Use --all to show results for all teams.
        """
        channel = msg.args[0]
        if channel == irc.nick:
            channel = msg.nick
        options = dict(options)
        date = options.get("date")
        if "all" in options:
            all = True
        else:
            all = False
        if date:
            if date.lower() in ["yesterday", "tomorrow", "today"]:
                if date.lower() in "yesterday":
                    date = pendulum.yesterday().format("YYYYMMDD")
                elif date.lower() in "tomorrow":
                    date = pendulum.tomorrow().format("YYYYMMDD")
                else:
                    date = pendulum.now().format("YYYYMMDD")
            else:
                try:
                    date = pendulum.parse(date, strict=False).format("YYYYMMDD")
                except:
                    irc.reply("Invalid date format")
                    return
            SCORES = self._checkscores(date)
            if date not in SCORES:
                niceDate = pendulum.parse(date)
                niceDate = "{0}/{1}/{2}".format(
                    niceDate.month, niceDate.day, niceDate.year
                )
                irc.reply("No games found for {}.".format(date))
        else:
            today = pendulum.now().format("YYYYMMDD")
            yesterday = pendulum.yesterday().format("YYYYMMDD")
            tomorrow = date = pendulum.tomorrow().format("YYYYMMDD")
            SCORES = self._checkscores()
            if today in SCORES:
                date = today
            elif yesterday in SCORES:
                date = yesterday
            elif tomorrow in SCORES:
                date = tomorrow
            else:
                irc.reply("No games found.")
                return

        if team:
            if len(team) > 2:
                reply = []
                # single team
                for key, value in SCORES[date].items():
                    if team.lower() in value["lookup"]["abbr"].lower():
                        # print(team.lower(), '\t', value['lookup']['abbr'].lower())
                        reply.append(value["long"])
                        # break
                if not reply:
                    for key, value in SCORES[date].items():
                        if team.lower() in value["lookup"]["full"].lower():
                            reply.append(value["long"])
                            # break
                if not reply:
                    irc.reply("ERROR: no match found for your input: {}".format(team))
                    return
                else:
                    if len(reply) <= 4:
                        for item in reply:
                            irc.sendMsg(ircmsgs.privmsg(channel, item))
                    else:
                        for item in reply:
                            irc.reply(item)
                return
            else:
                irc.reply("ERROR: search string too short")
                return
        else:
            niceDate = pendulum.parse(date)
            niceDate = "{0}/{1}/{2}".format(niceDate.month, niceDate.day, niceDate.year)
            reply = " | ".join(
                value["short"] for item, value in SCORES[date].items() if value["top25"]
            )
            if reply and not all:
                irc.reply(
                    "Showing teams in the top 25 for {0}. Use --all to see more games."
                    .format(niceDate),
                    prefixNick=False,
                )
                irc.reply(reply, prefixNick=False)
            else:
                reply = " | ".join(
                    value["short"] for item, value in SCORES[date].items()
                )
                irc.reply(
                    "Showing all games for {0}.".format(niceDate), prefixNick=False
                )
                irc.reply(reply, prefixNick=False)
            return

        return

    ######################
    # INTERNAL FUNCTIONS #
    ######################

    def _checkscores(self, cdate=None):
        if cdate:
            # today = pendulum.parse(cdate, strict=False).format('YYYYMMDD')
            # yesterday = pendulum.parse(cdate, strict=False).subtract(days=1).format('YYYYMMDD')
            # tomorrow = pendulum.parse(cdate, strict=False).add(days=1).format('YYYYMMDD')
            dates = [cdate]
        else:
            today = pendulum.now().format("YYYYMMDD")
            yesterday = pendulum.yesterday().format("YYYYMMDD")
            tomorrow = pendulum.tomorrow().format("YYYYMMDD")
            dates = [yesterday, today, tomorrow]

        data = collections.OrderedDict()
        for date in dates:
            tmp = requests.get(SCOREBOARD.format(date=date), timeout=10)
            tmp = json.loads(tmp.content)
            tmp_date = (
                pendulum.parse(tmp["eventsDate"]["date"], strict=False)
                .in_tz("US/Eastern")
                .format("YYYYMMDD")
            )
            data[tmp_date] = tmp["events"]

        # print(data)
        """
        'day': {'game1': {'short', 'long'},
                'game2': {'short', 'long'}}
        """
        games = collections.OrderedDict()
        for day, d in data.items():
            # print(day, d)
            if d:
                games[day] = collections.OrderedDict()
                for event in d:
                    key = event["id"]
                    lookup = {
                        "abbr": "{}".format(event["shortName"]),
                        "full": "{}".format(event["name"]),
                    }
                    comp = event["competitions"][0]
                    time = pendulum.parse(comp["date"], strict=False).in_tz(
                        "US/Eastern"
                    )
                    short_time = time.format("h:mm A zz")
                    long_time = time.format("dddd, MMM Do, h:mm A zz")
                    status = comp["status"]["type"]["state"]
                    is_ended = comp["status"]["type"]["completed"]
                    top25 = (
                        True
                        if (
                            0 < comp["competitors"][0]["curatedRank"]["current"] <= 25
                            or 0
                            < comp["competitors"][1]["curatedRank"]["current"]
                            <= 25
                        )
                        else False
                    )
                    home_rank = (
                        "(#{})".format(comp["competitors"][0]["curatedRank"]["current"])
                        if 0 < comp["competitors"][0]["curatedRank"]["current"] <= 25
                        else ""
                    )
                    away_rank = (
                        "(#{})".format(comp["competitors"][1]["curatedRank"]["current"])
                        if 0 < comp["competitors"][1]["curatedRank"]["current"] <= 25
                        else ""
                    )
                    home_short = comp["competitors"][0]["team"]["abbreviation"]
                    home_long = comp["competitors"][0]["team"]["displayName"]
                    away_short = comp["competitors"][1]["team"]["abbreviation"]
                    away_long = comp["competitors"][1]["team"]["displayName"]
                    home_score = int(comp["competitors"][0]["score"])
                    away_score = int(comp["competitors"][1]["score"])
                    broadcasts = []
                    try:
                        for thing in comp["broadcasts"]:
                            for station in thing["names"]:
                                broadcasts.append(station)
                    except:
                        pass
                    # print(home_short, away_short, '\t||\t', top25, status, comp['competitors'][0]['curatedRank']['current'],
                    #                                                       comp['competitors'][1]['curatedRank']['current'])
                    if status == "pre":
                        # pre
                        short = "{} @ {} {}".format(away_short, home_short, short_time)
                        long = "{}{} @ {}{} | {}{}".format(
                            away_long,
                            away_rank,
                            home_long,
                            home_rank,
                            long_time,
                            " [TV: {}]".format(
                                ", ".join(broadcasts) if broadcasts else ""
                            ),
                        )
                    else:
                        # inp
                        if is_ended:
                            clock_short = ircutils.mircColor("F", "red")
                            clock_long = ircutils.mircColor("Final", "red")
                        else:
                            if "Halftime" in comp["status"]["type"]["detail"]:
                                clock_short = ircutils.mircColor("HT", "orange")
                                clock_long = ircutils.mircColor("Halftime", "orange")
                            else:
                                clock_short = ircutils.mircColor(
                                    comp["status"]["type"]["shortDetail"].replace(
                                        " - ", " "
                                    ),
                                    "green",
                                )
                                clock_long = ircutils.mircColor(
                                    comp["status"]["type"]["detail"], "green"
                                )
                        try:
                            last_play = (
                                " | \x02Last Play:\x02 {}".format(
                                    comp["situation"]["lastPlay"]["text"]
                                )
                                if "situation" in comp
                                else ""
                            )
                        except:
                            last_play = ""
                        if away_score > home_score:
                            away_short_str = ircutils.bold(
                                "{} {}".format(away_short, away_score)
                            )
                            away_long_str = ircutils.bold(
                                "{}{} {}".format(away_long, away_rank, away_score)
                            )
                            home_short_str = "{} {}".format(home_short, home_score)
                            home_long_str = "{}{} {}".format(
                                home_long, home_rank, home_score
                            )
                        elif home_score > away_score:
                            away_short_str = "{} {}".format(away_short, away_score)
                            away_long_str = "{}{} {}".format(
                                away_long, away_rank, away_score
                            )
                            home_short_str = ircutils.bold(
                                "{} {}".format(home_short, home_score)
                            )
                            home_long_str = ircutils.bold(
                                "{}{} {}".format(home_long, home_rank, home_score)
                            )
                        else:
                            away_short_str = "{} {}".format(away_short, away_score)
                            away_long_str = "{}{} {}".format(
                                away_long, away_rank, away_score
                            )
                            home_short_str = "{} {}".format(home_short, home_score)
                            home_long_str = "{}{} {}".format(
                                home_long, home_rank, home_score
                            )
                        short = "{} {} {}".format(
                            away_short_str, home_short_str, clock_short
                        )
                        long = "{} @ {} - {}{}".format(
                            away_long_str, home_long_str, clock_long, last_play
                        )
                    games[day][key] = {
                        "short": short,
                        "long": long,
                        "ended": is_ended,
                        "top25": top25,
                        "lookup": lookup,
                    }

                # sort events
                games[day] = collections.OrderedDict(
                    sorted(games[day].items(), key=lambda k: k[1]["ended"])
                )

        return games


Class = CBB


# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
