# -*- coding: utf-8 -*-

import discord
import asyncio
#import pickle
import codecs
import string
import json
import random
#import math
import os

from funcs import helloFunc, cap, imageFunc, logThis, findWikiPage, makeFiles, emojiToNumber, fiarReactionTest, deleteGame, stopServer, checkBalance, giveMoney, triviaCountPoints, triviaStart, triviaAnswer, blackjackShuffle, blackjackStart, blackjackPlayerDrawHand, blackjackContinue, blackjackFinish, blackjackHit, blackjackStand, blackjackDouble, blackjackSplit, parseFourInARow, fourInARowAI, spellFunc, monsterFunc, nameGen, tavernGen, movieFunc, roll_dice, parseChar, parseRoll, critRoll, parseDestiny, parseHex, addToDict

from gameLoops import fiar, blackjackLoop, runHex

commandPrefix = "!"

# Blackjack shuffle variables
blackjackMinCards = 50
blackjackDecks = 4

# Variable for reacting to messages
meanWords = ["stupid", "bitch", "fuck", "dumb", "idiot"]

async def parseCommands(message,content):
    # Sends the contents of a help file, as specified by the message.
    if content.startswith("help"):
        try:
            if content == "help" or content == "help ":
                try:
                    with codecs.open("resources/help/help.txt",encoding="utf-8") as f:
                        text = f.read()
                    em = discord.Embed(title = "Help", description = text,colour = 0x59f442)
                    await message.channel.send(embed = em)
                except:
                    logThis("Couldn't find help.txt (error code 101)",str(message.channel))
                    await message.channel.send("Couldn't find help.txt (error code 101)")
            else:
                command = content.replace(" ","-")
                logThis("Looking for "+command+".txt",str(message.channel))
                try:
                    with codecs.open("resources/help/"+command+".txt",encoding="utf-8") as f:
                        text = f.read()
                    em = discord.Embed(title = command.replace("help-","").capitalize(), description = text,colour = 0x59f442)
                    await message.channel.send(embed = em)
                except:
                    logThis("Couldn't find help for that command (error code 102)",str(message.channel))
                    await message.channel.send("Couldn't find help for that command (error code 102)")
        except:
            logThis("Something fucked up (error code 100)",str(message.channel))
            await message.channel.send("Something fucked up (error code 100)")

    # Logs whatever you write in the message
    elif content.startswith("log "):
        logThis(content.replace("log ",""),str(message.channel))

    # Stops the bot
    elif content.startswith("stop"):
        try:
            if "#"+str(message.author.id) in ["#266269899859427329", "#380732645602230272"]:
                await message.channel.send("Logging out...")

                stopServer()

                await client.logout()
            else:
                logThis(message.author.display_name+" tried to run stop me! (error code 201)",str(message.channel))
                await message.channel.send("I don't think I will, "+message.author.display_name+" (error code 201)")
        except:
            logThis("Something fucked up (error code 200)",str(message.channel))
            await message.channel.send("Something fucked up (error code 200)")

    # Does a hello with the helloFunc function from funcs/gwendolynpy
    elif content.startswith("hello"):
        try:
            await message.channel.send(helloFunc(message.author.display_name))
        except:
            logThis("Something fucked up (error code 310)",str(message.channel))
            await message.channel.send("Something fucked up (error code 310)")

    # Rolls dice with the roll_dice function from funcs/roll/dice.py
    elif content.startswith("roll"):
        try:
            if content == "roll" or content == "roll ":
                await message.channel.send(roll_dice(message.author.display_name))
            else:
                await message.channel.send(roll_dice(message.author.display_name, content.replace("roll","")))
        except:
            logThis("Something fucked up (error code 400)",str(message.channel))
            await message.channel.send("Something fucked up (error code 400)")

    # Looks up a spell with the spellFunc function from funcs/lookup/lookuppy
    elif content.startswith("spell "):
        try:
            spell = spellFunc(cap(content.replace("spell","")))
            if len(spell) > 2000:
                await message.channel.send(spell[:2000])
                await message.channel.send(spell[2000:])
            else:
                await message.channel.send(spell)
        except:
            logThis("Something fucked up (error code 500)",str(message.channel))
            await message.channel.send("Something fucked up (error code 500)")

    # Looks up a monster with the monsterFuncs() from funcs/lookup/lookuppy
    elif content.startswith("monster "):
        try:
            title, text1, text2, text3, text4, text5 = monsterFunc(cap(content.replace("monster","")))
            em1 = discord.Embed(title = title, description = text1, colour=0xDEADBF)

            # Sends the received information. Seperates into seperate messages if
            # there is too much text
            await message.channel.send(embed = em1)
            if text2 != "":
                if len(text2) < 2048:
                    em2 = discord.Embed(title = "Special Abilities", description = text2, colour=0xDEADBF)
                    await message.channel.send(embed = em2)
                else:
                    em2 = discord.Embed(title = "Special Abilities", description = text2[:2048], colour=0xDEADBF)
                    await message.channel.send(embed = em2)
                    em2_2 = discord.Embed(title = "", description = text2[2048:], colour=0xDEADBF)
                    await message.channel.send(embed = em2_2)
            if text3 != "":
                if len(text3) < 2048:
                    em3 = discord.Embed(title = "Actions", description = text3, colour=0xDEADBF)
                    await message.channel.send(embed = em3)
                else:
                    em3 = discord.Embed(title = "Actions", description = text3[:2048], colour=0xDEADBF)
                    await message.channel.send(embed = em3)
                    em3_2 = discord.Embed(title = "", description = text3[2048:], colour=0xDEADBF)
                    await message.channel.send(embed = em3_2)
            if text4 != "":
                if len(text4) < 2048:
                    em4 = discord.Embed(title = "Reactions", description = text4, colour=0xDEADBF)
                    await message.channel.send(embed = em4)
                else:
                    em4 = discord.Embed(title = "Reactions", description = text4[:2048], colour=0xDEADBF)
                    await message.channel.send(embed = em4)
                    em4_2 = discord.Embed(title = "", description = text4[2048:], colour=0xDEADBF)
                    await message.channel.send(embed = em4_2)
            if text5 != "":
                if len(text5) < 2048:
                    em5 = discord.Embed(title = "Legendary Actions", description = text5, colour=0xDEADBF)
                    await message.channel.send(embed = em5)
                else:
                    em5 = discord.Embed(title = "Legendary Actions", description = text5[:2048], colour=0xDEADBF)
                    await message.channel.send(embed = em5)
                    em5_2 = discord.Embed(title = "", description = text5[2048:], colour=0xDEADBF)
                    await message.channel.send(embed = em5_2)
        except:
            logThis("Something fucked up (error code 600)",str(message.channel))
            await message.channel.send("Something fucked up (error code 600)")

    # Sends an image of the Senkulpa map
    elif content.startswith("map"):
        try:
            await message.channel.send("https://i.imgur.com/diMXXJs.jpg")
        except:
            logThis("Something fucked up (error code 320)",str(message.channel))
            await message.channel.send("Something fucked up (error code 320)")

    # Finds a random image on the internet with the imageFuncs function from
    # funcs/gwendolynpy
    elif content.startswith("image"):
        try:
            randomImage = imageFunc()
            await message.channel.send(randomImage)
        except:
            logThis("Something fucked up (error code 700)",str(message.channel))
            await message.channel.send("Something fucked up (error code 700)")

    # Sends information about a random movie with the movieFunc function from
    # funcs/other/movie.py
    elif content.startswith("movie"):
        try:
            async with message.channel.typing():
                title, plot, cover, cast = movieFunc()
                if title == "error":
                    await message.channel.send("An error occurred. Try again (error code "+plot+")")
                else:
                    try:
                        embed = discord.Embed(title=title, description=plot, color=0x24ec19)
                        embed.set_thumbnail(url=cover)
                        embed.add_field(name="Cast", value=cast,inline = True)
                        await message.channel.send(embed = embed)
                    except:
                        logThis("Error embedding (error code 805)")
        except:
            logThis("Something fucked up (error code 800)",str(message.channel))
            await message.channel.send("Something fucked up (error code 800)")

    # Generates a random name with the nameGen function from funcs/other/generators.py
    elif content.startswith("name"):
        try:
            await message.channel.send(nameGen())
        except:
            logThis("Something fucked up (error code 330)",str(message.channel))
            await message.channel.send("Something fucked up (error code 330)")

    # Generates a random tavern name with the tavernGen function from funcs/other/generators.py
    elif content.startswith("tavern"):
        try:
            await message.channel.send(tavernGen())
        except:
            logThis("Something fucked up (error code 340)",str(message.channel))
            await message.channel.send("Something fucked up (error code 340)")

    # Changes the "Playing this game" thing in Discord
    elif content.startswith("game "):
        try:
            gamePlaying = cap(content.replace("game ",""))
            game = discord.Game(gamePlaying)
            await client.change_presence(activity=game)
        except:
            logThis("Something fucked up (error code 350)",str(message.channel))
            await message.channel.send("Something fucked up (error code 350)")

    # Rolls star wars dice with the parseRoll function from funcs/swfuncs/swroll.py
    elif content.startswith("swroll"):
        try:
            command = cap(content.replace("swroll",""))
            newMessage = parseRoll("#"+str(message.author.id),command)
            messageList = newMessage.split("\n")
            for messageItem in messageList:
                await message.channel.send(messageItem)
        except:
            logThis("Something fucked up (error code 910)",str(message.channel))
            await message.channel.send("Something fucked up (error code 910)")

    # Deals with Destiny Points and stuff
    elif content.startswith("swd"):
        try:
            command = content.replace("swd","")
            newMessage = parseDestiny("#"+str(message.author.id),command)
            messageList = newMessage.split("\n")
            for messageItem in messageList:
                await message.channel.send(messageItem)
        except:
            logThis("Something fucked up (error code 920)",str(message.channel))
            await message.channel.send("Something fucked up (error code 920)")

    # Rolls for critical injuries
    elif content.startswith("swcrit"):
        try:
            command = content.replace("swcrit","").replace(" ","").replace("+","")

            if command == "":
                command = 0

            try:
                newMessage = critRoll(int(command))
            except:
                logThis("They didn't include a number (error code 931)",str(message.channel))
                newMessage = "Try using a number, stupid (error code 931)"

            messageList = newMessage.split("\n")
            for messageItem in messageList:
                await message.channel.send(messageItem)
        except:
            logThis("Something fucked up (error code 930)",str(message.channel))
            await message.channel.send("Something fucked up (error code 930)")

    # Accesses and changes character sheet data with the parseChar function
    # from funcs/swfuncs/swchar.py
    elif content.startswith("swchar") or content.startswith("sw"):
        try:
            command = string.capwords(content.replace("swchar","").replace("sw","").replace("+","+ ").replace("-","- ").replace(",",", "))
            title, desc = parseChar("#"+str(message.author.id),command)
            if title != "":
                em1 = discord.Embed(title = title, description = desc, colour=0xDEADBF)
                await message.channel.send(embed = em1)
            else:
                await message.channel.send(desc)
        except:
            logThis("Something fucked up (error code 940)",str(message.channel))
            await message.channel.send("Something fucked up (error code 940)")


    # Searches for a specific page on the Senkulpa Wiki
    elif content.startswith("wiki "):
        try:
            async with message.channel.typing():
                command = string.capwords(content.replace("wiki ",""))
                title, content, thumbnail = findWikiPage(command)
                if title != "":
                    logThis("Sending the embedded message",str(message.channel))
                    content += "\n[Læs mere](https://senkulpa.fandom.com/da/wiki/"+title.replace(" ","_")+")"
                    embed = discord.Embed(title = title, description = content, colour=0xDEADBF)
                    if thumbnail != "":
                        embed.set_thumbnail(url=thumbnail)

                    await message.channel.send(embed = embed)
                else:
                    await message.channel.send(content)
        except:
            logThis("Something fucked up (error code 1000)",str(message.channel))
            await message.channel.send("Something fucked up (error code 1000)")


    # Runs a trivia game
    elif content.startswith("trivia"):
        try:
            if content == "trivia" or content == "trivia ":
                question, answers, correctAnswer = triviaStart(str(message.channel))
                if answers != "":
                    results = "**"+question+"**\n"
                    for answer in range(len(answers)):
                        results += chr(answer+97) + ") "+answers[answer]+"\n"

                    await message.channel.send(results)

                    await asyncio.sleep(60)

                    triviaCountPoints(str(message.channel))

                    deleteGame("trivia questions",str(message.channel))

                    logThis("Time's up for the trivia question",str(message.channel))
                    await message.channel.send("Time's up The answer was \""+chr(correctAnswer)+") "+answers[correctAnswer-97]+"\". Anyone who answered that has gotten 1 GwendoBuck")
                else:
                    await message.channel.send(question)

            elif content.startswith("trivia "):
                command = content.replace("trivia ","")
                response = triviaAnswer("#"+str(message.author.id),str(message.channel),command)
                if response.startswith("Locked in "):
                    await message.add_reaction("👍")
                else:
                    await message.channel.send(response)
            else:
                logThis("I didn't understand that (error code 1101)",str(message.channel))
                await message.channel.send("I didn't understand that (error code 1101)")
        except:
            logThis("Something fucked up (error code 1100)",str(message.channel))
            await message.channel.send("Something fucked up (error code 1100)")


    # Checks your GwendoBucks balance
    elif content.startswith("balance"):
        try:
            response = checkBalance("#"+str(message.author.id))
            if response == 1:
                new_message = message.author.display_name + " has " + str(response) + " GwendoBuck"
            else:
                new_message = message.author.display_name + " has " + str(response) + " GwendoBucks"
            await message.channel.send(new_message)
        except:
            logThis("Something fucked up (error code 1210)",str(message.channel))
            await message.channel.send("Something fucked up (error code 1210)")

    # Gives money to other player
    elif content.startswith("give "):
        try:
            commands = content.split(" ")
            if len(commands) >= 3:
                try:
                    amount = int(commands[2])
                except:
                    logThis("Conversion error (error code 1221)",str(message.channel))
                    await message.channel.send("I didn't quite understand that (error code 1221)")
                else:
                    response = giveMoney("#"+str(message.author.id),commands[1],amount)
                    await message.channel.send(response)
            else:
                logThis("I didn't understand that (error code 1222)",str(message.channel))
                await message.channel.send("I didn't understand that (error code 1222)")
        except:
                logThis("Something fucked up (error code 1220)",str(message.channel))
                await message.channel.send("Something fucked up (error code 1220)")

    # Runs a game of Blackjack
    elif content.startswith("blackjack"):
        try:
            # Starts the game
            if content == "blackjack" or content == "blackjack ":
                cardsLeft = 0
                if os.path.exists("resources/games/blackjackCards/"+str(message.channel)+".txt"):
                    with open("resources/games/blackjackCards/"+str(message.channel)+".txt","r") as f:
                        for _ in f:
                            cardsLeft += 1

                # Shuffles if not enough cards
                if cardsLeft < blackjackMinCards:
                    blackjackShuffle(blackjackDecks,str(message.channel))
                    logThis("Shuffling the blackjack deck...",str(message.channel))
                    await message.channel.send("Shuffling the deck...")

                new_message = blackjackStart(str(message.channel))
                if new_message == "started":

                    new_message = "Blackjack game started. Use \""+commandPrefix+"blackjack bet [amount]\" to enter the game within the next 30 seconds."
                    await message.channel.send(new_message)
                    oldImage = await message.channel.send(file = discord.File("resources/games/blackjackTables/blackjackTable"+str(message.channel)+".png"))

                    with open("resources/games/oldImages/blackjack"+str(message.channel), "w") as f:
                        f.write(str(oldImage.id))

                    await asyncio.sleep(30)

                    gamedone = False

                    with open("resources/games/games.json", "r") as f:
                        data = json.load(f)
                        if len(data["blackjack games"][str(message.channel)]["user hands"]) == 0:
                            gamedone = True
                            await message.channel.send("No one entered the game. Ending the game.")
                        gameID = data["blackjack games"][str(message.channel)]["id"]

                    # Loop of game rounds
                    if gamedone == False:
                        logThis("!blackjack calling blackjackLoop()",str(message.channel))
                        await blackjackLoop(message.channel,1,gameID)
                    else:
                        new_message = blackjackFinish(str(message.channel))
                        await message.channel.send(new_message)
                else:
                    await message.channel.send(new_message)

            # Entering game and placing bet
            elif content.startswith("blackjack bet"):
                commands = content.split(" ")
                try:
                    amount = int(commands[2])
                except:
                    logThis("I didn't understand that",str(message.channel))
                    response = "I didn't understand that"
                else:
                    response = blackjackPlayerDrawHand(str(message.channel),"#"+str(message.author.id),amount)
                await message.channel.send(response)

            # Hitting
            elif content.startswith("blackjack hit"):
                if content == "blackjack hit" or content == "blackjack hit ":
                    response = blackjackHit(str(message.channel),"#"+str(message.author.id))
                else:
                    commands = content.split(" ")
                    try:
                        handNumber = int(commands[2])
                    except:
                        handNumber = 0
                    response = blackjackHit(str(message.channel),"#"+str(message.author.id),handNumber)

                if response.startswith("accept"):
                    await message.add_reaction("👍")
                    try:
                        if response[6] == "T":
                            with open("resources/games/games.json", "r") as f:
                                gameID = json.load(f)["blackjack games"][str(message.channel)]["id"]
                            logThis("Hit calling blackjackLoop()",str(message.channel))
                            await blackjackLoop(message.channel,int(response[7:])+1,gameID)
                    except:
                        logThis("Something fucked up (error code 1320)",str(message.channel))
                else:
                    await message.channel.send(response)


            # Standing
            elif content.startswith("blackjack stand"):
                if content == "blackjack hit" or content == "blackjack hit ":
                    response = blackjackStand(str(message.channel),"#"+str(message.author.id))
                else:
                    commands = content.split(" ")
                    try:
                        handNumber = int(commands[2])
                    except:
                        handNumber = 0
                    response = blackjackStand(str(message.channel),"#"+str(message.author.id),handNumber)

                if response.startswith("accept"):
                    await message.add_reaction("👍")
                    try:
                        if response[6] == "T":
                            with open("resources/games/games.json", "r") as f:
                                gameID = json.load(f)["blackjack games"][str(message.channel)]["id"]
                            logThis("Stand calling blackjackLoop()",str(message.channel))
                            await blackjackLoop(message.channel,int(response[7:])+1,gameID)
                    except:
                        logThis("Something fucked up (error code 1320)",str(message.channel))
                else:
                    await message.channel.send(response)

            # Doubling bet
            elif content.startswith("blackjack double"):
                commands = content.split(" ")
                try:
                    handNumber = int(commands[2])
                except:
                    handNumber = 0
                response, roundDone = blackjackDouble(str(message.channel),"#"+str(message.author.id),handNumber)

                await message.channel.send(response)

                try:
                    if roundDone[0] == "T":
                        with open("resources/games/games.json", "r") as f:
                            gameID = json.load(f)["blackjack games"][str(message.channel)]["id"]
                        logThis("Double calling blackjackLoop()",str(message.channel))
                        await blackjackLoop(message.channel,int(roundDone[1:])+1,gameID)
                except:
                    logThis("Something fucked up (error code 1320)",str(message.channel))

            # Splitting hand
            elif content.startswith("blackjack split"):
                commands = content.split(" ")
                try:
                    handNumber = int(commands[2])
                except:
                    handNumber = 0
                response, roundDone = blackjackSplit(str(message.channel),"#"+str(message.author.id),handNumber)

                await message.channel.send(response)

                try:
                    if roundDone[0] == "T":
                        with open("resources/games/games.json", "r") as f:
                            gameID = json.load(f)["blackjack games"][str(message.channel)]["id"]
                        logThis("Split calling blackjackLoop()",str(message.channel))
                        await blackjackLoop(message.channel,int(roundDone[1:])+1,gameID)
                except:
                    logThis("Something fucked up (error code 1320)")

            # Returning current hi-lo value
            elif content.startswith("blackjack hilo") and "#"+str(message.author.id) == "#266269899859427329":
                if os.path.exists("resources/games/blackjackCards/"+str(message.channel)+".txt"):
                    with open("resources/games/hilo/"+str(message.channel)+".txt", "r") as f:
                        data = f.read()
                else:
                    data = "0"
                await message.channel.send(data)

            # Shuffles the blackjack deck
            elif content.startswith("blackjack shuffle"):
                blackjackShuffle(blackjackDecks,str(message.channel))
                logThis("Shuffling the blackjack deck...",str(message.channel))
                await message.channel.send("Shuffling the deck...")


            # Tells you the amount of cards left
            elif content.startswith("blackjack cards"):
                cardsLeft = 0
                if os.path.exists("resources/games/blackjackCards/"+str(message.channel)+".txt"):
                    with open("resources/games/blackjackCards/"+str(message.channel)+".txt","r") as f:
                        for _ in f:
                            cardsLeft += 1

                decksLeft = round(cardsLeft/52,1)
                await message.channel.send(str(cardsLeft)+" cards, "+str(decksLeft)+" decks")

            else:
                logThis("Not a command (error code 1301)")
                await message.channel.send("I didn't quite understand that (error code 1301)")
        except:
            logThis("Something went wrong (error code 1300)")

    # Runs a game of four in a row
    elif content.startswith("fourinarow"):
        try:
            command = content.replace("fourinarow","")
            await fiar(message.channel,command,"#"+str(message.author.id))
        except:
            logThis("Something went wrong (error code 1400)")

    # Runs a game of Hex
    elif content.startswith("hex"):
        try:
            command = content.replace("hex","")
            await runHex(message.channel,command,"#"+str(message.author.id))
        except:
            logThis("Something went wrong (error code 1500)")
    
    # Not a command
    else:
        logThis("That's not a command (error code 001)",str(message.channel))
        await message.channel.send("That's not a command (error code 001)")

# Makes files if they don't exist yet
makeFiles()

# Gets secret bot token
with open("token.txt","r") as f:
    token = f.read().replace("\n","")

client = discord.Client()

# Logs in
@client.event
async def on_ready():
    logThis("Logged in as "+client.user.name+", "+str(client.user.id))
    game = discord.Game("Some weeb shit")
    await client.change_presence(activity=game)

# Reads messages and tests if they are Gwendolyn commands
@client.event
async def on_message(message):
    try:
        content = message.content
        if content.startswith(commandPrefix):
            logThis(message.author.display_name+" ("+"#"+str(message.author.id)+") ran \""+content+"\"",str(message.channel))
            addToDict("#"+str(message.author.id),message.author.display_name)
            await parseCommands(message,content.lower()[1:])
    except:
        logThis("Something fucked up (error code 000)")
        await message.channel.send("Something fucked up (error code 000)")

    # Is a bit sassy sometimes
    if ("gwendolyn" in message.content.lower() or message.content.startswith(commandPrefix)) and any(x in message.content.lower() for x in meanWords) and "ikke" not in message.content.lower() and "not" not in message.content.lower():
        logThis(message.author.display_name+" was a bit mean",str(message.channel))
        emoji = random.choice(["😠", "🖕", "👎"])
        await message.add_reaction(emoji)

@client.event
async def on_reaction_add(reaction,user):
    if user.bot == False:
        message = reaction.message
        channel = message.channel
        logThis(user.display_name+" reacted to a message",str(channel))
        fourInARowTheirTurn, piece = fiarReactionTest(channel,message,"#"+str(user.id))

        if fourInARowTheirTurn:
            place = emojiToNumber(reaction.emoji)
            await fiar(channel," place "+str(piece)+" "+str(place),user.id)

# Runs the whole shabang
client.run(token)
