import json
import string
import discord

class StarWarsChar():
    def __init__(self, bot):
        self.bot = bot

    def getCharName(self, user : str):
        self.bot.log("Getting name for "+self.bot.database_funcs.get_name(user)+"'s character")
        userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

        if userCharacter != None:
            self.bot.log("Name is "+userCharacter["Name"])
            return userCharacter["Name"]
        else:
            self.bot.log("Just using "+self.bot.database_funcs.get_name(user))
            return self.bot.database_funcs.get_name(user)

    def setUpDict(self, cmd : dict):
        self.bot.log("Setting up a dictionary in a nice way")
        if bool(cmd):
            keys = list(cmd)
            values = list(cmd.values())
            result = ""
            if isinstance(values[0],dict):
                return ", ".join(values)
            else:
                for x, key in enumerate(keys):
                    if type(key) is list:
                        if x%3 != 2:
                            result += "**" + key + "**" + ": " + ", ".join(values[x]) + " "
                        else:
                            result += "**" + key + "**" + ": " + ", ".join(values[x]) + "\n"
                    else:
                        if x%3 != 2:
                            result += "**" + key + "**" + ": " + str(values[x]) + " "
                        else:
                            result += "**" + key + "**" + ": " + str(values[x]) + "\n"
                self.bot.log("Returning a dictionary, but well formatted")
                return result
        else:
            self.bot.log("Couldn't find anything")
            return "There doesn't seem to be anything here..."

    def lookUp(self, data : dict, key : str, cmd : str = ""):
        if cmd == " ":
            cmd = ""
        elif cmd != "":
            while cmd[0] == " ":
                cmd = cmd[1:]
                if cmd == "":
                    break

        self.bot.log("Looking up "+key)
        if key in data:
            self.bot.log(key+" exists")
            if cmd == "":
                if type(data[key]) is dict and key != "Weapons":
                    return self.setUpDict(data[key])
                elif key == "Weapons":
                    self.bot.log("Does this even get used? I'm too scared to delete it")
                    if bool(data[key]):
                        self.bot.log("Found "+(", ".join(list(data[key]))))
                        return ", ".join(list(data[key]))
                    else:
                        self.bot.log("There is nothing here")
                        return "There doesn't seem to be anything here..."
                else:
                    if str(data[key]) != "":
                        self.bot.log("Returning "+str(data[key]))
                        return data[key]
                    else:
                        self.bot.log("There was nothing there")
                        return "There doesn't seem to be anything here"
            elif cmd[0] == '+':
                self.bot.log("Trying to add to "+key)
                try:
                    cmd = cmd[1:]
                    while cmd[0] == ' ':
                        cmd = cmd[1:]
                except:
                    self.bot.log("Yeah, that fucked up")
                    return "Can't do that"

                if type(data[key]) is int:
                    try:
                        newValue = data[key] + int(cmd)
                        data[key] = newValue
                        self.bot.log("Added "+cmd+" to "+key)
                        return data
                    except:
                        self.bot.log("Couldn't add "+cmd+" to "+key)
                        return "Can't add that"
                elif type(data[key]) is list:
                        try:
                            data[key].append(cmd)
                            self.bot.log("Added "+cmd+" to "+key)
                            return data
                        except:
                            self.bot.log("Couldn't add "+cmd+" to "+key)
                            return "Can't add that"
                else:
                    self.bot.log("Yeah, I can't add that to "+key)
                    return "Can't add that"

            elif cmd[0] == '-':
                self.bot.log("Trying to remove/subtract from "+key)
                try:
                    cmd = cmd[1:]
                    while cmd[0] == ' ':
                        cmd = cmd[1:]
                except:
                    self.bot.log("Yeah, that fucked up")
                    return "Can't do that"

                if type(data[key]) is int:
                    try:
                        newValue = data[key] - int(cmd)
                        data[key] = newValue
                        self.bot.log("Subtracted "+cmd+" from "+key)
                        return data
                    except:
                        self.bot.log("Couldn't subtract "+cmd+" from "+key)
                        return "Can't remove that"
                elif type(data[key]) is list:
                        try:
                            data[key].remove(cmd)
                            self.bot.log("Removed "+cmd+" from "+key)
                            return data
                        except:
                            self.bot.log("Couldn't remove "+cmd+" from "+key)
                            return "Can't remove that"
                else:
                    self.bot.log("Yeah, I can't remove/subtract that from "+key)
                    return "Can't remove that"
            else:
                while cmd[0] == ' ':
                    cmd = cmd[1:]

                if type(data[key]) is dict:
                    newKey = cmd.split(" ")[0]
                    cmd = cmd[len(newKey):]
                    if cmd != "":
                        while cmd[0] == " ":
                            cmd = cmd[1:]
                            if cmd == "":
                                break
                    self.bot.log("Looking up "+newKey+" in "+key)
                    lookUpResult = self.lookUp(data[key],newKey,cmd)
                    if type(lookUpResult) is dict:
                        data[key] = lookUpResult
                        return data
                    else:
                        return lookUpResult
                elif type(data[key]) != list:
                    self.bot.log("Trying to change "+key+" to "+cmd)
                    try:
                        cmd = type(data[key])(cmd)
                        data[key] = cmd
                        self.bot.log("Did that")
                        return data
                    except:
                        self.bot.log("No. That did not work")
                        return "Wrong data type"
                else:
                    self.bot.log("Yeah, that didn't work")
                    return "Wrong data type"
        else:
            self.bot.log("Couldn't find "+key)
            self.bot.log("Testing to see if it's a multi-word key")
            cmd = key + " " + cmd
            words = cmd.split(" ")
            search = ""
            i = 0
            while search not in data:
                try:
                    search += " " + words[i]
                    i += 1
                except:
                    self.bot.log("It wasn't. "+search+" doesn't exist")
                    return search + " doesn't exist"
                if search[0] == " ":
                    search = search[1:]
            self.bot.log("Yeah! Did that! The key was "+search)

            cmd = cmd[len(search):]
            if cmd != "":
                while cmd[0] == " ":
                    cmd = cmd[1:]
                    if cmd == "":
                        break

            if cmd == "":
                self.bot.log("Returning "+search)
                return self.setUpDict(data[search])
            else:
                newKey = cmd.split(" ")[0]
                cmd = cmd[len(newKey):]
                if cmd != "":
                    while cmd[0] == " ":
                        cmd = cmd[1:]
                        if cmd == "":
                            break
                lookUpResult = self.lookUp(data[search],newKey,cmd)
                if type(lookUpResult) is dict:
                    data[search] = lookUpResult
                    return data
                else:
                    return lookUpResult

    def characterSheet(self,character : dict):
        self.bot.log("Setting up a character sheet for "+character["Name"])
        divider = "--------------------\n"
        name = character["Name"]
        textf = ""
        if character["Force-rating"] != 0:
            textf = "\n**Force Rating**: "+str(character["Force-rating"])

        text1 = "**Species**: "+character["Species"]+"\n**Career**: "+character["Career"]+"\n**Specialization Trees**: "+", ".join(character["Specialization-trees"])+textf+"\n**Soak**: "+str(character["Soak"])
        text2 = "\n\n**Wounds**: "+str(character["Wounds"])+"/"+str(character["Wound-threshold"])+"\n**Strain**: "+str(character["Strain"])+"/"+str(character["Strain-threshold"])
        text3 = self.setUpDict(character["Characteristics"])
        text4 = self.setUpDict(character["Skills"])
        text5 = ""
        text6 = ""
        text7 = ""
        text8 = ""

        if bool(character["Talents"]):
            text5 = "**Talents**: "+", ".join(list(character["Talents"]))+"\n\n"

        if bool(character["Force-powers"]):
            text6 = "**Force Powers**: "+", ".join(list(character["Force-powers"]))+"\n\n"

        text7 = "**Equipment**: "+", ".join(character["Equipment"])+"\n**Credits**: "+str(character["Credits"])+"\n**Weapons**: "+", ".join(list(character["Weapons"]))+"\n"+divider

        if bool(character["Obligations"]):
            text8 = "**Obligations**: "+",".join(list(character["Obligations"]))

        return name, text1+text2+"\n\n"+text3+divider+text4+"\n"+divider+text5+text6+text7+text8

    def charData(self,user : str,cmd : str):
        userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

        key = string.capwords(cmd.split(" ")[0])
        cmd = cmd[len(key):]
        if cmd == " ":
            cmd = ""
        elif cmd != "":
            while cmd[0] == " ":
                cmd = cmd[1:]
                if cmd == "":
                    break

        self.bot.log("Looking for "+self.bot.database_funcs.get_name(user)+"'s character")
        if userCharacter != None:
            self.bot.log("Found it! Looking for "+key+" in the data")
            if key in userCharacter:
                self.bot.log("Found it!")
                if type(userCharacter[key]) is dict:
                    self.bot.log("It's a dictionary!")
                    if cmd == "":
                        self.bot.log("Retrieving data")
                        if key == "Weapons":
                            if bool(userCharacter[key]):
                                self.bot.log("Returning a list of weapons")
                                return ", ".join(list(userCharacter[key]))
                            else:
                                self.bot.log("The character doesn't have any weapons. Which is probably for the best. Like, who just walks around with weapons? (error code 941)")
                                return "There doesn't seem to be anything there... (error code 941)"
                        else:
                            return self.setUpDict(userCharacter[key])
                    elif cmd[0] == "+":
                        self.bot.log("Gonna add something!!!")
                        try:
                            cmd = cmd[1:]
                            while cmd[0] == ' ':
                                cmd = cmd[1:]
                        except:
                            self.bot.log("Nope. That didn't happen (error code 942)")
                            return "Can't do that (error code 942)"

                        if (key == "Talents" or key == "Force-powers") and "," in cmd:
                            cmd = cmd.split(",")
                            while cmd[1][0] == " ":
                                cmd[1] = cmd[1][1:]
                            self.bot.log("Adding "+cmd[0]+" to "+key)
                            self.bot.database["starwars characters"].update_one({"_id":user},
                                {"$set": {key+"."+cmd[0] : cmd[1]}})
                            return cmd[0]+" added to "+key+" for " + userCharacter["Name"]

                        elif key == "Obligations" and "," in cmd:
                            cmd = cmd.split(",")
                            while cmd[1][0] == " ":
                                cmd[1] = cmd[1][1:]
                            self.bot.log("Adding "+cmd[0]+" to "+key)
                            try:
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$set": {key+"."+cmd[0] : int(cmd[1])}})
                            except:
                                self.bot.log("Fucked that up (error code 949)")
                                return "Wrong data type (error code 949)"
                            return cmd[0]+" added to "+key+" for " + userCharacter["Name"]

                        elif key == "Weapons":
                            with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as f:
                                templates = json.load(f)
                            newWeapon = templates["Weapon"]
                            self.bot.log("Adding "+cmd+" to "+key)
                            self.bot.database["starwars characters"].update_one({"_id":user},
                                {"$set": {key+"."+cmd : newWeapon}})

                            return cmd+" added to weapons for " + userCharacter["Name"]

                        else:
                            self.bot.log("That's not happening (error code 947d)")
                            return "Can't add that (error code 947d)"

                    elif cmd[0] == "-":
                        self.bot.log("Gonna subtract/remove something")
                        try:
                            cmd = cmd[1:]
                            while cmd[0] == ' ':
                                cmd = cmd[1:]
                        except:
                            self.bot.log("AAAAAAAAAAAA  (error code 948)")
                            return "Can't do that  (error code 948)"

                        if key == "Talents" or key == "Force-powers" or key == "Weapons" or key == "Obligations":
                            self.bot.log("Trying to remove "+cmd+" from "+key)
                            if cmd in userCharacter[key]:
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$unset": {cmd}})
                                self.bot.log("I did that")
                                return cmd+" removed from "+key+" from "+userCharacter["Name"]
                            else:
                                self.bot.log("Welp. I fucked that up (error code 946e)")
                                return "Can't remove that (error code 946e)"
                        else:
                            self.bot.log("Urgh! (error code 946d)")
                            return "Can't remove that (error code 946d)"

                    else:
                        self.bot.log("Looking up "+cmd+" in "+key)
                        if key == "Talents" or key == "Force-powers":
                            newKey = cmd
                            newcmd = ""
                        else:
                            newKey = string.capwords(cmd.split(" ")[0])
                            newcmd = cmd[len(newKey):]

                        lookUpResult = self.lookUp(userCharacter[key],newKey,newcmd)

                        if type(lookUpResult) is dict:
                            self.bot.database["starwars characters"].update_one({"_id":user},
                                {"$set": {key : lookUpResult}})
                            return "Changed " + userCharacter["Name"] + "'s " + key
                        else:
                            return lookUpResult
                else:
                    if cmd == "":
                        self.bot.log("Retrieving data")
                        if type(userCharacter[key]) is list:
                            return key+":\n"+", ".join(userCharacter[key])
                        else:
                            return userCharacter[key]
                    elif cmd[0] == '+':
                        self.bot.log("Adding")
                        try:
                            cmd = cmd[1:]
                            while cmd[0] == ' ':
                                cmd = cmd[1:]
                        except:
                            self.bot.log("Error message (error code 948)")
                            return "Can't do that (error code 948)"

                        if type(userCharacter[key]) is int:
                            try:
                                self.bot.log("Adding "+cmd+" to "+key)
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$inc": {key : int(cmd)}})
                                return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
                            except:
                                self.bot.log("BITCH SANDWICH (error code 947c)")
                                return "Can't add that (error code 947c)"
                        elif type(userCharacter[key]) is list:
                            try:
                                self.bot.log("Adding "+cmd+" to "+key)
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$push": {key : cmd}})
                                return "Added " + cmd + " to " + userCharacter["Name"] + "'s " + key
                            except:
                                self.bot.log("tstststststs (error code 947b)")
                                return "Can't add that (error code 947b)"
                        else:
                            self.bot.log("Help (error code 947a)")
                            return "Can't add that (error code 947a)"
                    elif cmd[0] == '-':
                        self.bot.log("Removing/subtracting")
                        try:
                            cmd = cmd[1:]
                            while cmd[0] == ' ':
                                cmd = cmd[1:]
                        except:
                            self.bot.log("lalalala  (error code 948)")
                            return "Can't do that (error code 948)"

                        if type(userCharacter[key]) is int:
                            try:
                                self.bot.log("Subtracting "+cmd+" from "+key)
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$inc": {key : -int(cmd)}})
                                return "Subtracted " + cmd + " from " + userCharacter["Name"] + "'s " + key
                            except:
                                self.bot.log("Tried it. Didn't want to (error code 946c)")
                                return "Can't remove that (error code 946c)"
                        elif type(userCharacter[key]) is list:
                            try:
                                self.bot.log("removing "+cmd+" from "+key)
                                try:
                                    self.bot.database["starwars characters"].update_one({"_id":user},
                                        {"$pull": {key : cmd}})
                                except:
                                    self.bot.log("They can only remove stuff that's actually in the list")
                                    return "Not in list (error code 944b)"
                                return "Removed " + cmd + " from " + userCharacter["Name"] + "'s " + key
                            except:
                                self.bot.log("nah (error code 946b)")
                                return "Can't remove that (error code 946b)"
                        else:
                            self.bot.log("nyope (error code 946a)")
                            return "Can't remove that (error code 946a)"
                    else:
                        self.bot.log("Changing "+key+" to "+cmd)
                        if type(userCharacter[key]) is int:
                            try:
                                self.bot.database["starwars characters"].update_one({"_id":user},
                                    {"$set": {key : int(cmd)}})
                            except:
                                self.bot.log("I don't wanna tho (error code 945b)")
                                return "Can't do that (error code 945b)"
                        elif type(userCharacter[key]) is str:
                            self.bot.database["starwars characters"].update_one({"_id":user},
                                {"$set": {key : cmd}})
                        else:
                            self.bot.log("I don't wanna tho (error code 945a)")
                            return "Can't do that (error code 945a)"
                        return "Changed " + userCharacter["Name"] + "'s " + key +" to " + cmd
            else:
                self.bot.log(key+" isn't in there (error code 944)")
                return "Couldn't find that data. Are you sure you spelled it correctly? (error code 944)"
        else:
            self.bot.log(user+" doesn't have a character (error code 943)")
            return "You don't have a character. You can make one with /starwarscharacter (error code 943)"

    def replaceSpaces(self,cmd : str):
        withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - Light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
        withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]

        for x, value in enumerate(withoutSpaces):
            cmd = cmd.replace(withSpaces[x],value)

        return cmd

    def replaceWithSpaces(self,cmd : str):
        withSpaces = ["Specialization Trees","Wound Threshold","Strain Threshold","Defense - Ranged","Defense - Melee","Force Rating","Core Worlds","Outer Rim","Piloting - Planetary","Piloting - Space","Ranged - Heavy","Ranged - light","Lightsaber Characteristic","Critical Injuries","Force Powers"]
        withoutSpaces = ["Specialization-trees","Wound-threshold","Strain-threshold","Defense-ranged","Defense-melee","Force-rating","Core-worlds","Outer-rim","Piloting-planetary","Piloting-space","Ranged-heavy","Ranged-light","Lightsaber-characteristic","Critical-injuries","Force-powers"]

        for x, value in enumerate(withoutSpaces):
            cmd = cmd.replace(value,withSpaces[x])

        return cmd

    async def parseChar(self, ctx, parameters : str):
        user = f"#{ctx.author.id}"
        cmd = string.capwords(parameters.replace("+","+ ").replace("-","- ").replace(",",", "))
        returnEmbed = False

        cmd = self.replaceSpaces(cmd)

        userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

        if cmd == " ":
            cmd = ""
        elif cmd != "":
            while cmd[0] == " ":
                cmd = cmd[1:]
                if cmd == "":
                    break


        if cmd == "":
            if userCharacter != None:
                title, text = self.characterSheet(userCharacter)
                text = self.replaceWithSpaces(text)
                returnEmbed = True
            else:
                self.bot.log("Makin' a character for "+self.bot.database_funcs.get_name(user))
                with open("gwendolyn/resources/star_wars/starwarstemplates.json", "r") as f:
                    templates = json.load(f)
                newChar = templates["Character"]
                newChar["_id"] = user
                self.bot.database["starwars characters"].insert_one(newChar)
                await ctx.send("Character for " + self.bot.database_funcs.get_name(user) + " created")
        else:
            if cmd == "Purge":
                self.bot.log("Deleting "+self.bot.database_funcs.get_name(user)+"'s character")
                self.bot.database["starwars characters"].delete_one({"_id":user})
                await ctx.send("Character for " + self.bot.database_funcs.get_name(user) + " deleted")
            else:
                await ctx.send(self.replaceWithSpaces(str(self.charData(user,cmd))))

        if returnEmbed:
            em = discord.Embed(title = title, description = text, colour=0xDEADBF)
            await ctx.send(embed = em)



    def lightsaberChar(self,user : str):
        userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

        if userCharacter != None:
            return userCharacter["Lightsaber-characteristic"]

    def userHasChar(self,user : str):
        userCharacter = self.bot.database["starwars characters"].find_one({"_id":user})

        return userCharacter != None

