import math
import json
import discord

from gwendolyn.utils import cap


class LookupFuncs():
    def __init__(self, bot):
        self.bot = bot
        self.saves = ["strength_save","dexterity_save","constitution_save","intelligence_save","wisdom_save","charisma_save"]
        self.abilities = ["acrobatics","animal_handling","arcana","athletics","deception","history","insight","intimidation","investigation","medicine","nature","perception","performance","persuasion","religion","sleight_of_hand","stealth","survival"]

    # Calculates D&D stat modifier
    def modifier(self, statistic):
        mods = math.floor((statistic-10)/2)
        if mods >= 0:
            mods = "+"+str(mods)
        return(str(mods))

    # Looks up a monster
    async def monsterFunc(self, ctx, query):
        query = cap(query)
        self.bot.log("Looking up "+query)

        # 1-letter monsters don't exist
        if len(query) < 2:
            self.bot.log("Monster name too short")
            await ctx.send("I don't know that monster...")
        else:
            # Opens "monsters.json"
            data = json.load(open('gwendolyn/resources/lookup/monsters.json', encoding = "utf8"))
            for monster in data:
                if "name" in monster and str(query) == monster["name"]:
                    self.bot.log("Found it!")

                    # Looks at the information about the monster and returns that information
                    # in separate variables, allowing Gwendolyn to know where to separate
                    # the messages
                    if monster["subtype"] != "":
                        types = (monster["type"]+" ("+monster["subtype"]+")")
                    else:
                        types = monster["type"]
                    con_mod = math.floor((monster["constitution"]-10)/2)
                    hit_dice = monster["hit_dice"]

                    stats = ("**Str:** "+str(monster["strength"])+" ("+self.modifier(monster["strength"])+")\t**Dex:** "+str(monster["dexterity"])+" ("+self.modifier(monster["dexterity"])+")\t**Con:** "+str(monster["constitution"])+" ("+self.modifier(monster["constitution"])+")\n**Int: **"+str(monster["intelligence"])+" ("+self.modifier(monster["intelligence"])+")\t**Wis: **"+str(monster["wisdom"])+" ("+self.modifier(monster["wisdom"])+")\t**Cha: **"+str(monster["charisma"])+" ("+self.modifier(monster["charisma"])+")")

                    saving_throws = ""
                    for save in self.saves:
                        if save in monster:
                            if monster[save] >= 0:
                                saving_throws += " "+cap(save[:3])+" +"+str(monster[save])+","
                            else:
                                saving_throws += " "+cap(save[:3])+" "+str(monster[save])+","
                    if saving_throws != "":
                        saving_throws = "\n**Saving Throws**"+saving_throws[:-1]

                    skills = ""
                    for skill in self.abilities:
                        if skill in monster:
                            if monster[skill] >= 0:
                                skills += " "+cap(skill.replace("_"," "))+" +"+str(monster[skill])+","
                            else:
                                skills += " "+cap(skill.replace("_"," "))+" "+str(monster[skill])+","
                    if skills != "":
                        skills = "\n**Skills**"+skills[:-1]

                    vulnerabilities = monster["damage_vulnerabilities"]
                    if vulnerabilities != "":
                        vulnerabilities = "\n**Damage Vulnerabilities** "+vulnerabilities

                    resistances = monster["damage_resistances"]
                    if resistances != "":
                        resistances = "\n**Damage Resistances** "+resistances

                    immunities = monster["damage_immunities"]
                    if immunities != "":
                        immunities = "\n**Damage Immunities** "+immunities

                    c_immunities = monster["condition_immunities"]
                    if c_immunities != "":
                        c_immunities = "\n**Condition Immunities** "+c_immunities

                    specialAbilities = ""
                    if "special_abilities" in monster:
                        for ability in monster["special_abilities"]:
                            specialAbilities += "\n\n***"+ability["name"]+".*** "+ability["desc"]

                    act = ""
                    if "actions" in monster:
                        for action in monster["actions"]:
                            act += "\n\n***"+action["name"]+".*** "+action["desc"]

                    react = ""
                    if "reactions" in monster:
                        for reaction in monster["reactions"]:
                            react += "\n\n***"+reaction["name"]+".*** "+reaction["desc"]

                    legendaryActions = ""
                    if "legendary_actions" in monster:
                        for action in monster["legendary_actions"]:
                            legendaryActions += "\n\n***"+action["name"]+".*** "+action["desc"]

                    if con_mod < 0:
                        hit_dice += (" - "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])*(-1)))
                    if con_mod > 0:
                        hit_dice += (" + "+str(con_mod * int(monster["hit_dice"].replace("d"," ").split()[0])))

                    new_part = "\n--------------------"

                    monster_type = monster["size"]+" "+types+", "+monster["alignment"]+"*"

                    basic_info = "\n**Armor Class** "+str(monster["armor_class"])+"\n**Hit Points** "+str(monster["hit_points"])+" ("+hit_dice+")\n**Speed **"+monster["speed"]+new_part+"\n"

                    info = (monster_type+new_part+basic_info+stats+new_part+saving_throws+skills+vulnerabilities+resistances+immunities+c_immunities+"\n**Senses** "+monster["senses"]+"\n**Languages** "+monster["languages"]+"\n**Challenge** "+monster["challenge_rating"])

                    monsterInfo = [(info, query),
                                   (specialAbilities, "Special Abilities"),
                                   (act, "Actions"),
                                   (react, "Reactions"),
                                   (legendaryActions, "Legendary Actions")]

                    self.bot.log("Returning monster information")

                    # Sends the received information. Separates into separate messages if
                    # there is too much text
                    await ctx.send(f"Result for \"{query}\"")
                    for text, title in monsterInfo:
                        if text != "":
                            if len(text) < 2000:
                                em = discord.Embed(title = title, description = text, colour=0xDEADBF)
                                await ctx.channel.send(embed = em)
                            else:
                                index = text[:2000].rfind(".")+1
                                em1 = discord.Embed(title = title, description = text[:index], colour=0xDEADBF)
                                await ctx.channel.send(embed = em1)
                                em2 = discord.Embed(title = "", description = text[index+1:], colour=0xDEADBF)
                                await ctx.channel.send(embed = em2)

                    break
            else:
                self.bot.log("Monster not in database")
                await ctx.send("I don't know that monster...")

    # Looks up a spell
    async def spellFunc(self, ctx, query):
        query = cap(query)
        self.bot.log("Looking up "+query)

        # Opens "spells.json"
        data = json.load(open('gwendolyn/resources/lookup/spells.json', encoding = "utf8"))
        if query in data:
            self.bot.log("Returning spell information")
            sendMessage = (f"***{query}***\n*{data[query]['level']} level {data[query]['school']}\nCasting Time: {data[query]['casting_time']}\nRange:{data[query]['range']}\nComponents:{data[query]['components']}\nDuration:{data[query]['duration']}*\n \n{data[query]['description']}")
        else:
            self.bot.log("I don't know that spell (error code 501)")
            sendMessage = "I don't think that's a spell (error code 501)"

        if len(sendMessage) > 2000:
            await ctx.send(sendMessage[:2000])
            await ctx.send(sendMessage[2000:])
        else:
            await ctx.send(sendMessage)
