import logging
import re

import irc.client

from ircbot.lib import Plugin, reply_destination_for_event
from ircbot.models import IrcChannel
import markov.lib as markovlib

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


class Markov(Plugin):

    """Build Markov chains and reply with them."""

    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'^!markov\s+reply(\s+min=(\d+))?(\s+max=(\d+))?(\s+(.*)$|$)',
                                                         self.handle_reply, -20)

        super(Markov, 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_reply)

        super(Markov, self).stop()

    def handle_reply(self, connection, event, match):
        """Generate a reply to one line, without learning it."""

        target = reply_destination_for_event(event)

        min_size = 15
        max_size = 30
        context = markovlib.get_or_create_target_context(target)

        if match.group(2):
            min_size = int(match.group(2))
        if match.group(4):
            max_size = int(match.group(4))

        if match.group(5) != '':
            line = match.group(6)
            topics = [x for x in line.split(' ') if len(x) >= 3]

            return self.bot.reply(event, " ".join(markovlib.generate_line(context, topics=topics,
                                                                          min_words=min_size, max_words=max_size,
                                                                          max_sentences=1)))
        else:
            return self.bot.reply(event, " ".join(markovlib.generate_line(context, min_words=min_size,
                                                                          max_words=max_size,
                                                                          max_sentences=1)))

    def handle_chatter(self, connection, event):
        """Learn from IRC chatter."""

        what = event.arguments[0]
        my_nick = connection.get_nickname()
        trimmed_what = re.sub(r'^{0:s}[:,]\s+'.format(my_nick), '', what)
        nick = irc.client.NickMask(event.source).nick
        target = reply_destination_for_event(event)

        # check to see whether or not we should learn from this channel
        channel = None
        if irc.client.is_channel(target):
            channel, c = IrcChannel.objects.get_or_create(name=target)

        if channel and not channel.markov_learn_from_channel:
            log.debug("not learning from %s as i've been told to ignore it", channel)
        else:
            # learn the line
            recursing = getattr(event, '_recursing', False)
            if not recursing:
                log.debug("learning %s", trimmed_what)
                context = markovlib.get_or_create_target_context(target)
                markovlib.learn_line(trimmed_what, context)

        log.debug("searching '%s' for '%s'", what, my_nick)
        if re.search(my_nick, what, re.IGNORECASE) is not None:
            context = markovlib.get_or_create_target_context(target)

            addressed_pattern = r'^{0:s}[:,]\s+(.*)'.format(my_nick)
            addressed_re = re.compile(addressed_pattern)
            if addressed_re.match(what):
                # i was addressed directly, so respond, addressing
                # the speaker
                topics = [x for x in addressed_re.match(what).group(1).split(' ') if len(x) >= 3]

                return self.bot.reply(event, "{0:s}: {1:s}"
                                      "".format(nick, " ".join(markovlib.generate_line(context,
                                                                                       topics=topics,
                                                                                       max_sentences=1))))
            else:
                # i wasn't addressed directly, so just respond
                topics = [x for x in what.split(' ') if len(x) >= 3]

                return self.bot.reply(event, "{0:s}"
                                      "".format(" ".join(markovlib.generate_line(context,
                                                                                 topics=topics,
                                                                                 max_sentences=1))))


plugin = Markov