package com.loganmagnan.eventcore.utils;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import lombok.Getter;
import lombok.Setter;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;

@Getter
@Setter
public class CachedInventory {

    private ItemStack[] cachedInventory;

    private ItemStack[] cachedArmor;

    public CachedInventory() {

    }

    private double health = -1.0D;

    private int totalExperience = -1;
    private int food = -1;

    private float exp = -1.0F;

    public CachedInventory(Player player, boolean justContents) {
        this.cachedInventory = player.getInventory().getContents();
        this.cachedArmor = player.getInventory().getArmorContents();
        if (!justContents) {
            this.health = player.getHealth();
            this.food = player.getFoodLevel();
            this.totalExperience = player.getTotalExperience();
            this.exp = player.getExp();
        }
    }

    private void delayedUpdateInventory(final Player player, JavaPlugin plugin) {
        (new BukkitRunnable() {
            public void run() {
                player.updateInventory();
            }
        }).runTaskLater((Plugin)plugin, 1);
    }

    public static CachedInventory fromPlayer(Player player, boolean justContents) {
        return new CachedInventory(player, justContents);
    }

    public void applyToPlayer(Player player, boolean justContents) {
        player.getInventory().setContents(this.cachedInventory);
        player.getInventory().setArmorContents(this.cachedArmor);
        if (!justContents) {
            if (this.health > 0.0D)
                player.setHealth(this.health);
            if (this.food != -1)
                player.setFoodLevel(this.food);
            if (this.totalExperience != -1)
                player.setTotalExperience(this.totalExperience);
            if (this.exp != -1.0F)
                player.setExp(this.exp);
        }
    }

    public void applyToPlayer(Player player, boolean justContents, JavaPlugin plugin) {
        applyToPlayer(player, justContents);
        delayedUpdateInventory(player, plugin);
    }

    public static CachedInventory fromConfigurationSection(ConfigurationSection section) {
        CachedInventory cachedInventory = new CachedInventory();
        List<String> armorArray = section.getStringList("armor");
        List<ItemStack> armor = new ArrayList<>();
        armorArray.forEach(armorElement -> {
            try {
                armor.add(ItemBuilder.itemFrom64(armorElement));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        cachedInventory.setCachedArmor((ItemStack[])armor.stream().toArray(x$0 -> new ItemStack[x$0]));
        List<String> invArray = section.getStringList("inv");
        List<ItemStack> inv = new ArrayList<>();
        invArray.forEach(invElement -> {
            try {
                inv.add(ItemBuilder.itemFrom64(invElement));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        cachedInventory.setCachedInventory((ItemStack[])inv.stream().toArray(x$0 -> new ItemStack[x$0]));
        if (section.contains("health"))
            cachedInventory.setHealth(section.getDouble("health"));
        if (section.contains("totalExperience"))
            cachedInventory.setHealth(section.getInt("totalExperience"));
        if (section.contains("food"))
            cachedInventory.setHealth(section.getInt("food"));
        if (section.contains("exp"))
            cachedInventory.setHealth(section.getInt("exp"));
        return cachedInventory;
    }

    public ConfigurationSection toConfigurationSection(Configuration configuration, String sectionName) {
        ConfigurationSection section = configuration.createSection(sectionName);
        if (this.health != -1.0D)
            section.set("health", Double.valueOf(this.health));
        if (this.totalExperience != -1)
            section.set("totalExperience", Integer.valueOf(this.totalExperience));
        if (this.food != -1)
            section.set("food", Integer.valueOf(this.food));
        if (this.exp != -1.0F)
            section.set("exp", Float.valueOf(this.exp));
        List<String> armor = new ArrayList<>();
        for (ItemStack armorItem : getCachedArmor())
            armor.add(ItemBuilder.itemTo64(armorItem));
        section.set("armor", armor);
        List<String> inv = new ArrayList<>();
        for (ItemStack invItem : getCachedInventory())
            inv.add(ItemBuilder.itemTo64(invItem));
        section.set("inv", inv);
        return section;
    }

    public static CachedInventory fromJson(JsonObject jsonObject) {
        CachedInventory cachedInventory = new CachedInventory();
        JsonArray armorArray = jsonObject.get("armor").getAsJsonArray();
        List<ItemStack> armor = new ArrayList<>();
        armorArray.forEach(armorElement -> {
            try {
                armor.add(ItemBuilder.itemFrom64(armorElement.getAsString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        cachedInventory.setCachedArmor(armor.toArray(new ItemStack[0]));
        JsonArray invArray = jsonObject.get("inv").getAsJsonArray();
        List<ItemStack> inv = new ArrayList<>();
        invArray.forEach(invElement -> {
            try {
                inv.add(ItemBuilder.itemFrom64(invElement.getAsString()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        cachedInventory.setCachedInventory(inv.toArray(new ItemStack[0]));
        if (jsonObject.has("health"))
            cachedInventory.setHealth(jsonObject.get("health").getAsDouble());
        if (jsonObject.has("totalExperience"))
            cachedInventory.setHealth(jsonObject.get("totalExperience").getAsInt());
        if (jsonObject.has("food"))
            cachedInventory.setHealth(jsonObject.get("food").getAsInt());
        if (jsonObject.has("exp"))
            cachedInventory.setHealth(jsonObject.get("exp").getAsFloat());
        return cachedInventory;
    }

    public JsonObject toJson() {
        JsonObject jsonObject = new JsonObject();
        if (this.health != -1.0D)
            jsonObject.addProperty("health", this.health);
        if (this.totalExperience != -1)
            jsonObject.addProperty("totalExperience", this.totalExperience);
        if (this.food != -1)
            jsonObject.addProperty("food", this.food);
        if (this.exp != -1.0F)
            jsonObject.addProperty("exp", this.exp);
        JsonArray armorArray = new JsonArray();
        for (ItemStack itemStack : this.cachedArmor)
            armorArray.add(new JsonPrimitive(ItemBuilder.itemTo64(itemStack)));
        jsonObject.add("armor", armorArray);
        JsonArray invArray = new JsonArray();
        for (ItemStack itemStack : this.cachedInventory)
            invArray.add(new JsonPrimitive(ItemBuilder.itemTo64(itemStack)));
        jsonObject.add("inv", invArray);
        return jsonObject;
    }
}