"""
Commands:
.autoop add/del/status/list
.op

Nick-format: nick!ident@example.org

Supports adding/deleting multiple autoop-rules:
.autoop add #testchannel firstNick!ident@example.org secNick!ident@example.org

In add/del #channel needed, if changes done in query. If changes are made in #channel, defaults to current #channel.

config-file in root/modules/module_autooop.conf
config-format:
 'nick!ident@example.org':
 - '#channelOne'
 - '#channelTwo'

 'secNick!ident@example.org':
 - '#channelTwo'
"""

import fnmatch
import yaml
import os.path
import sys
import re

oplistfile = os.path.join(sys.path[0], "modules", "module_autoop.conf")
oplist = dict()


def init(botconfig):
    global oplist
    if os.path.exists(oplistfile):
        oplist = yaml.load(file(oplistfile), Loader=yaml.FullLoader)


def writeConfig():
    # open file for writing (note, removes all markings that have been made to config-file prior to .rehash
    f = open(oplistfile, "w")
    yaml.dump(oplist, f, default_flow_style=False)
    f.close()


def isAutoOppable(user, channel):
    for pattern in oplist:
        if fnmatch.fnmatch(user, pattern):
            if channel in oplist[pattern]:
                return True


def handle_userJoined(bot, user, channel):
    if isAdmin(user) or isAutoOppable(user, channel):
        nick = getNick(user)
        bot.log("auto-opping %s on %s" % (user, channel))
        bot.mode(channel, True, "o", user=nick)


def handle_args(args, channel):
    message = ""
    nicks = list()
    rg = re.compile(
        ".*?(!).*?(@).*?", re.IGNORECASE | re.DOTALL
    )  # regex for validating nick format
    if re.match(rg, args[0].strip()) is None and args[0].strip()[0] == "#":
        op_channel = args[0].strip()
        for nick in args[1:]:
            if re.match(rg, nick):
                nicks.append(nick)
            else:
                message += "%s not in correct format. " % nick
    else:
        op_channel = channel
        for nick in args[0:]:
            if re.match(rg, nick):
                nicks.append(nick)
            else:
                message += "%s not in correct format. " % nick
    return nicks, op_channel, message


def autoop_status(user, channel, args):
    nick = getNick(user)
    if isAdmin(user):
        return "%s: you are %s on %s, status: bot admin" % (nick, user, channel)
    elif isAutoOppable(user, channel):
        return "%s: you are %s on %s, status: auto-op" % (nick, user, channel)
    else:
        return "%s: you are %s on %s: status: -" % (nick, user, channel)


def autoop_add(user, channel, args):
    if isAdmin(user):
        nicks = list()
        message = ""
        if len(args) > 0:
            nicks, op_channel, message = handle_args(args, channel)
            if cmp(op_channel, user) != 0:
                for nick in nicks:
                    if (
                        nick in oplist
                    ):  # if already in oplist, just add to existing list
                        if (
                            op_channel in oplist[nick]
                        ):  # if not in nicks channel list, add
                            message += "Auto-op for %s already in %s. " % (
                                nick,
                                op_channel,
                            )
                        else:
                            message += "Auto-op for %s in %s added. " % (
                                nick,
                                op_channel,
                            )
                            oplist[nick].append(op_channel)
                    else:
                        message += "Auto-op for %s in %s added. " % (nick, op_channel)
                        oplist[nick] = list()
                        oplist[nick].append(op_channel)
                writeConfig()
            else:
                message = "#channel always needed when making changes in query!"
            return message
        else:
            return "Usage: .autoop add [#channel] nick!ident@hostma.sk"


def autoop_del(user, channel, args):
    if isAdmin(user):
        message = ""
        if len(args) > 0:
            nicks, op_channel, message = handle_args(args, channel)
            if cmp(op_channel, user) != 0:
                for nick in nicks:
                    if nick in oplist:
                        if (
                            op_channel in oplist[nick]
                        ):  # if in nicks channel list, remove
                            message += "Auto-op for %s in %s removed. " % (
                                nick,
                                op_channel,
                            )
                            oplist[nick].remove(op_channel)
                            if len(oplist[nick]) == 0:
                                del oplist[nick]
                        else:
                            message += "No auto-op for %s in %s. " % (nick, op_channel)
                    else:
                        message += "No auto-op for %s in %s. " % (nick, op_channel)
                writeConfig()
            else:
                message = "#channel always needed when making changes in query!"
            return message
        else:
            return "Usage: .autoop del [#channel] nick!ident@hostma.sk"


def autoop_list(user, channel, args):
    if isAdmin(user):
        i = 0
        rg = re.compile(
            ".*?(!).*?(@).*?", re.IGNORECASE | re.DOTALL
        )  # regex for validating nick format
        if (
            len(args) == 0
            or (re.match(rg, args[0].strip()) is None and args[0].strip()[0] == "#")
        ) and args[0] != "me":
            if len(args) == 0:
                op_channel = channel
            elif re.match(rg, args[0].strip()) is None and args[0].strip()[0] == "#":
                op_channel = args[0].strip()
            message = "Auto-ops in %s: " % op_channel
            for nick, channels in oplist.items():
                for chan in channels:
                    if chan == op_channel:
                        message += nick + " "
                        i = i + 1
            if i != 0:
                return message
            else:
                return "%s has no auto-ops." % op_channel
        elif re.match(rg, args[0].strip()) or args[0] == "me":
            if args[0] != "me":
                nick = args[0].strip()
            else:
                nick = user
            message = "%s auto-op in: " % nick
            if nick in oplist:
                for chan in oplist[nick]:
                    message += chan + " "
                    i = i + 1
            if i != 0:
                return message
            else:
                return "%s not auto-op anywhere." % nick
        else:
            return "Usage: .autoop_list [#channel _or_ nick!ident@hostma.sk]"
    else:
        nick = user
        i = 0
        message = "%s auto-op in: " % nick
        if nick in oplist:
            for chan in oplist[nick]:
                message += chan + " "
                i = i + 1
        if i != 0:
            return message
        else:
            return "%s not auto-op anywhere." % nick


def make_valid_commands_msg(commands):
    message = "Valid commands are: "
    for command in commands:
        message += command
        message += ", "
    message = message[:-2]
    message += "."
    return message


def command_op(bot, user, channel, args):
    if isAdmin(user) or isAutoOppable(user, channel):
        nick = getNick(user)
        bot.log("opping %s by request on %s" % (user, channel))
        bot.mode(channel, True, "o", user=nick)


def command_autoop(bot, user, channel, args):
    commands = {
        "add": autoop_add,
        "del": autoop_del,
        "list": autoop_list,
        "status": autoop_status,
    }
    args = args.split()
    if len(args) > 0:
        command = args[0]
        if command in commands:
            args.remove(command)
            message = commands[command](user, channel, args)
        else:
            message = make_valid_commands_msg(commands)
    else:
        message = make_valid_commands_msg(commands)
    return bot.say(channel, message)
