import json
import pickle
from os import urandom
from os.path import exists
from string import digits

from redis import StrictRedis

# List of errors ZNC can give us
ZNCErrors = ["Error:", "Unable to load", "does not exist", "doesn't exist"]

configPath = "conf/live/"
templateConfigPath = "conf/templates/"
certPath = "conf/cert/"

filemap = {
    # JSON configs
    "config": ["config.json", "configuration", "json"],
    "help": ["help.json", "command help", "json"],
    "counters": ["counters.json", "counters file", "json"],
    "tokens": ["tokens.json", "authentication tokens", "json"],
    "aliasdata": ["aliasdata.json", "data for alias generation", "json"],
    "alias": ["alias.json", "provisioned alias data", "json"],
    "irc": ["irc.json", "IRC network definitions", "json"],
    "blacklist": ["blacklist.json", "IRC channel blacklist", "json"],
    # Binary (pickle) configs
    "network": ["network.dat", "network list", "pickle"],
}

# Connections to the plain-text interface
connections = {}
# Connections to the JSON interface
relayConnections = {}

# Mapping of network names to Protocol (IRCClient) instances
IRCPool = {}

# Mapping of network names to Reactor instances
# Needed for calling .disconnect()
ReactorPool = {}

# Mapping of network names to Factory instances
# Needed for calling .stopTrying()
FactoryPool = {}

# Temporary store for channels allocated after a LIST
# Will get purged as the instances fire up and pop() from
#  their respective keys in here
TempChan = {}

# Mapping of command names to their functions
CommandMap = {}

# Incremented by 1 for each event reaching modules.counters.event()
#  and cloned into lastMinuteSample every minute
runningSample = 0
lastMinuteSample = 0

# Generate 16-byte hex key for message checksums
hashKey = urandom(16)
lastEvents = {}


# Get networks that are currently online and dedupliate
def liveNets():
    networks = set()
    for i in IRCPool.keys():
        networks.add("".join([x for x in i if x not in digits]))
    return networks


def saveConf(var):
    if var in ("help", "aliasdata"):
        return  # no need to save this
    if filemap[var][2] == "json":
        with open(configPath + filemap[var][0], "w") as f:
            json.dump(globals()[var], f, indent=4)
    elif filemap[var][2] == "pickle":
        with open(configPath + filemap[var][0], "wb") as f:
            pickle.dump(globals()[var], f)
    else:
        raise Exception("invalid format")


def loadConf(var):
    if filemap[var][2] == "json":
        filename = configPath + filemap[var][0]
        # Only take the help from the templates
        if var in ("help", "aliasdata"):
            filename = templateConfigPath + filemap[var][0]
        if not exists(filename):
            # Load the template config
            if var == "config":
                filename = templateConfigPath + filemap[var][0]
            else:
                # Everything else should be blank
                globals()[var] = {}
                return
        with open(filename, "r") as f:
            globals()[var] = json.load(f)
        if var == "alias":
            # This is a workaround to convert all the keys into integers since JSON
            #  turns them into strings...
            #  Dammit Jason!
            global alias
            alias = {int(x): y for x, y in alias.items()}

    elif filemap[var][2] == "pickle":
        try:
            with open(configPath + filemap[var][0], "rb") as f:
                globals()[var] = pickle.load(f)
        except FileNotFoundError:
            globals()[var] = {}
    else:
        raise Exception("invalid format")


def initConf():
    for i in filemap.keys():
        loadConf(i)


def initMain():
    global r, g
    initConf()
    r = StrictRedis(
        unix_socket_path=config["RedisSocket"], db=config["RedisDBEphemeral"]  # noqa
    )  # Ephemeral - flushed on quit
    g = StrictRedis(
        unix_socket_path=config["RedisSocket"], db=config["RedisDBPersistent"]
    )  # noqa
