"""
Contains functions relating to invest commands.

*Classes*
---------
    Invest
        Contains all the code for the invest commands.
"""
import discord  # Used for embeds
from discord_slash.context import SlashContext  # Used for type hints


class Invest():
    """
    Contains all the invest functions.

    *Methods*
    ---------
        getPrice(symbol: str) -> int
        getPortfolio(user: str) -> str
        buyStock(user: str, stock: str: buyAmount: int) -> str
        sellStock(user: str, stock: str, buyAmount: int) -> str
        parseInvest(ctx: discord_slash.context.SlashContext,
                    parameters: str)
    """

    def __init__(self, bot):
        """Initialize the class."""
        self.bot = bot

    def getPrice(self, symbol: str):
        """
        Get the price of a stock.

        *Parameters*
        ------------
            symbol: str
                The symbol of the stock to get the price of.

        *Returns*
        ---------
            price: int
                The price of the stock.
        """
        res = self.bot.finnhub_client.quote(symbol.upper())
        if res == {}:
            return 0
        else:
            return int(res["c"] * 100)

    def getPortfolio(self, user: str):
        """
        Get the stock portfolio of a user.

        *Parameters*
        ------------
            user: str
                The id of the user to get the portfolio of.

        *Returns*
        ---------
            portfolio: str
                The portfolio.
        """
        investmentsDatabase = self.bot.database["investments"]
        userInvestments = investmentsDatabase.find_one({"_id": user})

        user_name = self.bot.database_funcs.get_name(user)

        if userInvestments in [None, {}]:
            return f"{user_name} does not have a stock portfolio."
        else:
            portfolio = f"**Stock portfolio for {user_name}**"

            for key, value in list(userInvestments["investments"].items()):
                purchaseValue = value["purchased for"]
                stockPrice = self.getPrice(key)
                valueAtPurchase = value["value at purchase"]
                purchasedStock = value["purchased"]
                valueChange = (stockPrice / valueAtPurchase)
                currentValue = int(valueChange * purchasedStock)
                portfolio += f"\n**{key}**: ___{currentValue} GwendoBucks___"

                if purchaseValue != "?":
                    portfolio += f" (purchased for {purchaseValue})"

            return portfolio

    def buyStock(self, user: str, stock: str, buyAmount: int):
        """
        Buy an amount of a specific stock.

        *Paramaters*
        ------------
            user: str
                The id of the user buying.
            stock: str
                The symbol of the stock to buy.
            buyAmount: int
                The amount of GwendoBucks to use to buy the stock.

        *Returns*
        ---------
            sendMessage: str
                The message to return to the user.
        """
        if buyAmount < 100:
            return "You cannot buy stocks for less than 100 GwendoBucks"
        elif self.bot.money.checkBalance(user) < buyAmount:
            return "You don't have enough money for that"
        elif self.getPrice(stock) <= 0:
            return f"{stock} is not traded on the american market."
        else:
            investmentsDatabase = self.bot.database["investments"]
            stockPrice = self.getPrice(stock)
            userInvestments = investmentsDatabase.find_one({"_id": user})

            self.bot.money.addMoney(user, -1*buyAmount)
            stock = stock.upper()

            if userInvestments is not None:
                userInvestments = userInvestments["investments"]
                if stock in userInvestments:
                    value = userInvestments[stock]
                    valueChange = (stockPrice / value["value at purchase"])
                    currentValue = int(valueChange * value["purchased"])
                    newAmount = currentValue + buyAmount

                    valuePath = f"investments.{stock}.value at purchase"
                    updater = {"$set": {valuePath: stockPrice}}
                    investmentsDatabase.update_one({"_id": user}, updater)

                    purchasedPath = f"investments.{stock}.purchased"
                    updater = {"$set": {purchasedPath: newAmount}}
                    investmentsDatabase.update_one({"_id": user}, updater)

                    if value["purchased for"] != "?":
                        purchasedForPath = f"investments.{stock}.purchased for"
                        updater = {"$set": {purchasedForPath: buyAmount}}
                        investmentsDatabase.update_one({"_id": user}, updater)
                else:
                    updater = {
                        "$set": {
                            "investments.{stock}": {
                                "purchased": buyAmount,
                                "value at purchase": stockPrice,
                                "purchased for": buyAmount
                            }
                        }
                    }
                    investmentsDatabase.update_one({"_id": user}, updater)
            else:
                newUser = {
                    "_id": user,
                    "investments": {
                        stock: {
                            "purchased": buyAmount,
                            "value at purchase": stockPrice,
                            "purchased for": buyAmount
                        }
                    }
                }
                investmentsDatabase.insert_one(newUser)

            user_name = self.bot.database_funcs.get_name(user)
            sendMessage = "{} bought {} GwendoBucks worth of {} stock"
            sendMessage = sendMessage.format(user_name, buyAmount, stock)
            return sendMessage

    def sellStock(self, user: str, stock: str, sellAmount: int):
        """
        Sell an amount of a specific stock.

        *Paramaters*
        ------------
            user: str
                The id of the user selling.
            stock: str
                The symbol of the stock to sell.
            buyAmount: int
                The amount of GwendoBucks to sell for.

        *Returns*
        ---------
            sendMessage: str
                The message to return to the user.
        """
        if sellAmount <= 0:
            return "no"
        else:
            investmentsDatabase = self.bot.database["investments"]
            userData = investmentsDatabase.find_one({"_id": user})
            userInvestments = userData["investments"]

            stock = stock.upper()

            if userInvestments is not None and stock in userInvestments:
                value = userInvestments[stock]
                stockPrice = self.getPrice(stock)
                priceChange = (stockPrice / value["value at purchase"])
                purchasedAmount = int(priceChange * value["purchased"])
                purchasedPath = f"investments.{stock}.purchased"
                updater = {"$set": {purchasedPath: purchasedAmount}}
                investmentsDatabase.update_one({"_id": user}, updater)
                valueAtPurchasePath = f"investments.{stock}.value at purchase"
                updater = {"$set": {valueAtPurchasePath: stockPrice}}
                investmentsDatabase.update_one({"_id": user}, updater)
                if value["purchased"] >= sellAmount:
                    self.bot.money.addMoney(user, sellAmount)
                    if sellAmount < value["purchased"]:
                        purchasedPath = f"investments.{stock}.purchased"
                        updater = {"$inc": {purchasedPath: -sellAmount}}
                        investmentsDatabase.update_one({"_id": user}, updater)

                        purchasedForPath = f"investments.{stock}.purchased for"
                        updater = {"$set": {purchasedForPath: "?"}}
                        investmentsDatabase.update_one({"_id": user}, updater)
                    else:
                        updater = {"$unset": {f"investments.{stock}": ""}}
                        investmentsDatabase.update_one({"_id": user}, updater)

                    user_name = self.bot.database_funcs.get_name(user)
                    sendMessage = "{} sold {} GwendoBucks worth of {} stock"
                    return sendMessage.format(user_name, sellAmount, stock)
                else:
                    return f"You don't have enough {stock} stocks to do that"
            else:
                return f"You don't have any {stock} stock"

    async def parseInvest(self, ctx: SlashContext, parameters: str):
        """
        Parse an invest command. TO BE DELETED.

        *Parameters*
        ------------
            ctx: discord_slash.context.SlashContext
                The context of the slash command.
            parameters: str
                The parameters of the command.
        """
        await self.bot.defer(ctx)
        user = f"#{ctx.author.id}"

        if parameters.startswith("check"):
            commands = parameters.split(" ")
            if len(commands) == 1:
                response = self.getPortfolio(user)
            else:
                price = self.getPrice(commands[1])
                if price == 0:
                    response = "{} is not traded on the american market."
                    response = response.format(commands[0].upper())
                else:
                    price = f"{price:,}".replace(",", ".")
                    response = self.bot.long_strings["Stock value"]
                    response = response.format(commands[1].upper(), price)

        elif parameters.startswith("buy"):
            commands = parameters.split(" ")
            if len(commands) == 3:
                response = self.buyStock(user, commands[1], int(commands[2]))
            else:
                response = self.bot.long_strings["Stock parameters"]

        elif parameters.startswith("sell"):
            commands = parameters.split(" ")
            if len(commands) == 3:
                response = self.sellStock(user, commands[1], int(commands[2]))
            else:
                response = self.bot.long_strings["Stock parameters"]

        else:
            response = "Incorrect parameters"

        if response.startswith("**"):
            responses = response.split("\n")
            text = "\n".join(responses[1:])
            embedParams = {
                "title": responses[0],
                "description": text,
                "colour": 0x00FF00
            }
            em = discord.Embed(**embedParams)
            await ctx.send(embed=em)
        else:
            await ctx.send(response)
