"""Karma hooks for the IRC bot."""

import logging
import re

import irc.client

from django.conf import settings

from ircbot.lib import Plugin
from karma.models import KarmaKey, KarmaLogEntry

log = logging.getLogger('karma.ircplugin')


class Karma(Plugin):

    """Track karma and report on it."""

    def start(self):
        """Set up the handlers."""

        self.connection.add_global_handler('pubmsg', self.handle_chatter, -20)
        self.connection.add_global_handler('privmsg', self.handle_chatter, -20)

        self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'],
                                                         r'^!karma\s+rank\s+(.*)$',
                                                         self.handle_rank, -20)
        self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'],
                                                         (r'^!karma\s+report\s+(highest|lowest|positive|negative'
                                                          r'|top|opinionated)'),
                                                         self.handle_report, -20)
        self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'],
                                                         r'^!karma\s+stats\s+([\S]+)',
                                                         self.handle_stats, -20)

        super(Karma, self).start()

    def stop(self):
        """Tear down handlers."""

        self.connection.remove_global_handler('pubmsg', self.handle_chatter)
        self.connection.remove_global_handler('privmsg', self.handle_chatter)

        self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_rank)
        self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_report)
        self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_stats)

        super(Karma, self).stop()

    @staticmethod
    def handle_chatter(connection, event):
        """Watch karma from IRC chatter."""

        what = event.arguments[0].lower()
        karma_pattern = r'(?:\((.+?)\)|(\S+))(\+\+|--|\+-|-\+)(\s+|$)'

        where = event.target
        if where in settings.KARMA_IGNORE_CHATTER_TARGETS:
            log.debug("ignoring chatter in {0:s}".format(where))
            return

        # check the line for karma
        log.debug("searching '%s' for karma", what)
        matches = re.findall(karma_pattern, what, re.IGNORECASE)
        for match in matches:
            key = match[0] if match[0] else match[1]
            value = match[2]

            karma_key, c = KarmaKey.objects.get_or_create(key=key)

            if value == '++':
                KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source)
            elif value == '--':
                KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source)
            elif value == '+-':
                KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source)
                KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source)
            elif value == '-+':
                KarmaLogEntry.objects.create(key=karma_key, delta=-1, nickmask=event.source)
                KarmaLogEntry.objects.create(key=karma_key, delta=1, nickmask=event.source)

    def handle_rank(self, connection, event, match):
        """Report on the rank of a karma item."""

        where = event.target
        if where in settings.KARMA_IGNORE_COMMAND_TARGETS:
            log.debug("ignoring command in {0:s}".format(where))
            return

        key = match.group(1).lower().rstrip()
        try:
            karma_key = KarmaKey.objects.get(key=key)
            return self.bot.reply(event, "{0:s} has {1:d} points of karma (rank {2:d})".format(karma_key.key,
                                                                                               karma_key.score(),
                                                                                               karma_key.rank()))
        except KarmaKey.DoesNotExist:
            return self.bot.reply(event, "i have not seen any karma for {0:s}".format(match.group(1)))

    def handle_report(self, connection, event, match):
        """Provide some karma reports."""

        where = event.target
        if where in settings.KARMA_IGNORE_COMMAND_TARGETS:
            log.debug("ignoring command in {0:s}".format(where))
            return

        report = match.group(1).lower()
        if report == 'highest':
            sorted_keys = KarmaKey.objects.ranked_scored_order()
            msg = "top 5 recipients: {0:s}".format(", ".join([str(x) for x in sorted_keys[:5]]))
            return self.bot.reply(event, msg)
        elif report == 'lowest':
            sorted_keys = KarmaKey.objects.ranked_scored_reverse_order()
            msg = "bottom 5 recipients: {0:s}".format(", ".join([str(x) for x in sorted_keys[:5]]))
            return self.bot.reply(event, msg)
        elif report == 'positive':
            karmaers = KarmaLogEntry.objects.optimists()
            karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick,
                                                             x['karma_outlook']) for x in karmaers])
            msg = "top 5 optimists: {0:s}".format(karmaer_list)
            return self.bot.reply(event, msg)
        elif report == 'negative':
            karmaers = KarmaLogEntry.objects.pessimists()
            karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick,
                                                             x['karma_outlook']) for x in karmaers])
            msg = "top 5 pessimists: {0:s}".format(karmaer_list)
            return self.bot.reply(event, msg)
        elif report == 'top' or report == 'opinionated':
            karmaers = KarmaLogEntry.objects.most_opinionated()
            karmaer_list = ", ".join(["{0:s} ({1:d})".format(irc.client.NickMask(x['nickmask']).nick,
                                                             x['karma_count']) for x in karmaers])
            msg = "top 5 opinionated users: {0:s}".format(karmaer_list)
            return self.bot.reply(event, msg)

    def handle_stats(self, connection, event, match):
        """Provide stats on a karma user."""

        where = event.target
        if where in settings.KARMA_IGNORE_COMMAND_TARGETS:
            log.debug("ignoring command in {0:s}".format(where))
            return

        karmaer = match.group(1)
        log_entries = KarmaLogEntry.objects.filter(nickmask=karmaer)
        if len(log_entries) == 0:
            # fallback, try to match the nick part of nickmask
            log_entries = KarmaLogEntry.objects.filter(nickmask__startswith='{0:s}!'.format(karmaer))

        if len(log_entries) == 0:
            return self.bot.reply(event, "karma user {0:s} not found".format(karmaer))

        total_karma = log_entries.count()
        positive_karma = log_entries.filter(delta__gt=0).count()
        negative_karma = log_entries.filter(delta__lt=0).count()
        msg = ("{0:s} has given {1:d} postive karma and {2:d} negative karma, for a total of {3:d} karma"
               "".format(karmaer, positive_karma, negative_karma, total_karma))
        return self.bot.reply(event, msg)


plugin = Karma