#!/usr/bin/python3 -s
import re
import sys
from l3tlib.command import L3tCommand

import six


try:
    import notmuch
except ImportError:
    sys.stderr.write("python2-notmuch is needed")
    sys.exit(1)

TAG_SEEN = "l3t-seen"
TAG_RUNNING = "l3t-running"
TAG_INBOX = "inbox"


class TagRunning(L3tCommand):

    usage = "%prog [OPTIONS] [NOTMUCH DATABASE PATH]"
    descr = """\
Tags in notmuch all the Bugzilla messages that are related to currently
running incidents.

The first run might take a long time, so invoke it manually first.

Messages tagged %s will get a tag %s. After that, only messages without %s
will be inspected.

The tag used for running incidents is %s.

If no database path is provided, it defaults to the output of
`notmuch config get database.path`.
""" % (TAG_INBOX, TAG_SEEN, TAG_SEEN, TAG_RUNNING)

    def bugs_actually_running(self):
        found = []
        for incidents in list(self.l3t.overview(active=True, sleeping=True,
                                           processed=True,
                                           backup=True).values()):
            found.extend(incident.bug_id for incident in incidents)
        return found

    def get_bug_id(self, msg):
        subject = msg.get_header("Subject")
        found = re.search("\[Bug (?P<bug_id>[^\]]+)\]", subject)
        bug_id = None
        if found:
            bug_id = int(found.group("bug_id"))
        return bug_id

    def unseen_messages(self, db):
        expr = "tag:%s AND NOT tag:%s" % (TAG_INBOX, TAG_SEEN)
        query = db.create_query(expr)
        return query.search_messages()

    def bugzilla_messages_tagged_running(self, db):
        expr = "tag:%s AND tag:%s" % (TAG_INBOX, TAG_RUNNING)
        query = db.create_query(expr)
        return query.search_messages()

    def remove_not_running_anymore(self, tagged_messages, running_bugs):
        for msg in tagged_messages:
            bug_id = self.get_bug_id(msg)
            if bug_id not in running_bugs:
                yield msg

    def tag_unseen_running(self, unseen, running_bugs):
        for msg in unseen:
            bug_id = self.get_bug_id(msg)
            if bug_id is not None and bug_id in running_bugs:
                yield msg

    def run(self):
        path = self.args[0] if self.args else None
        db = notmuch.Database(path=path, mode=notmuch.Database.MODE.READ_WRITE)
        try:
            running_bugs = self.bugs_actually_running()
            tagged_running = self.bugzilla_messages_tagged_running(db)
            to_remove = self.remove_not_running_anymore(tagged_running,
                                                        running_bugs)
            unseen = list(self.unseen_messages(db))
            six.print_("unseen", len(unseen))
            to_add = self.tag_unseen_running(unseen, running_bugs)
            for msg in to_remove:
                six.print_("not running:", msg.get_header("Subject"))
                msg.remove_tag(TAG_RUNNING)
            for msg in to_add:
                six.print_("new running:", msg.get_header("Subject"))
                msg.add_tag(TAG_RUNNING)
            for msg in unseen:
                msg.add_tag(TAG_SEEN)
        finally:
            print("closing db")
            db.close()


TagRunning().main()
