package leigh.minecraft.link.bukkit;

import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import net.milkbowl.vault.economy.Economy;
import net.milkbowl.vault.economy.EconomyResponse;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.RegisteredServiceProvider;

import static org.bukkit.Bukkit.getServer;

public class BukkitUtil {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(BukkitUtil.class);

    public static void giveItem(Player player, ItemStack stack, String title) {
        Inventory inv = Bukkit.getServer().createInventory(player, 9, title);
        inv.setItem(0, stack);
        player.openInventory(inv);
    }

    /**
     * Attempt to charge the given amount to the player. If the player's balance is insufficient, an
     * error message is sent to the player and <code>false</code> is returned.
     */
    public static boolean chargeMoney(Player player, int amt) {
        RegisteredServiceProvider<Economy> economyProvider =
                getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
        EconomyResponse er = economyProvider.getProvider().withdrawPlayer(player, amt);

        logger.info("Economy response: {} {}", er.transactionSuccess(), er.errorMessage);

        if (!er.transactionSuccess()) {
            player.sendMessage("Insufficient funds for transaction. [required: " + amt + "] [balance: " + er.balance + "]");
        }

        return er.transactionSuccess();
    }

    // Calculate amount of EXP needed to level up
    public static int getExpToLevelUp(int level) {
        if (level <= 15) {
            return 2 * level + 7;
        } else if (level <= 30) {
            return 5 * level - 38;
        } else {
            return 9 * level - 158;
        }
    }

    // Calculate total experience up to a level
    public static int getExpAtLevel(int level) {
        if (level <= 16) {
            return (int) (Math.pow(level, 2) + 6 * level);
        } else if (level <= 31) {
            return (int) (2.5 * Math.pow(level, 2) - 40.5 * level + 360.0);
        } else {
            return (int) (4.5 * Math.pow(level, 2) - 162.5 * level + 2220.0);
        }
    }

    // Calculate player's current EXP amount
    public static int getPlayerExp(Player player) {
        int exp = 0;
        int level = player.getLevel();

        // Get the amount of XP in past levels
        exp += getExpAtLevel(level);

        // Get amount of XP towards next level
        exp += Math.round(getExpToLevelUp(level) * player.getExp());

        return exp;
    }

    // Give or take EXP
    public static int changePlayerExp(Player player, int exp) {
        // Get player's current exp
        int currentExp = getPlayerExp(player);

        // Reset player's current exp to 0
        player.setExp(0);
        player.setLevel(0);

        // Give the player their exp back, with the difference
        int newExp = currentExp + exp;
        player.giveExp(newExp);

        // Return the player's new exp amount
        return newExp;
    }

}
