/*
 *   This file is a part of the SteamWar software.
 *
 *   Copyright (C) 2025 SteamWar.de-Serverteam
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *   GNU Affero General Public License for more details.
 *
 *   You should have received a copy of the GNU Affero General Public License
 *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package de.steamwar.misslewars.scripts;

import com.google.gson.JsonObject;
import de.steamwar.misslewars.scripts.utils.JsonUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static de.steamwar.misslewars.scripts.utils.JsonUtils.getString;

public class ScriptedItem {

    // "type": Material name (STRING)
    // "name": Item name (STRING)
    // "lore": Lore array (OPTIONAL STRING.ARRAY)
    // "amount": Item amount (OPTIONAL [default 1] INT)
    // "potion": Object with key value pairs for PotionType and Object containing duration and amplifier (OPTIONAL OBJECT)
    // "uses": Uses of Item (OPTIONAL INT)
    // "EVENT.<eventName>": Event (OPTIONAL JSONobject.ARRAY)
    // - onClick
    // - onHit
    // - onThrow

    public enum EventType {
        onHit,
        onThrow,
        onClick
    }

    private Map<EventType, Script> scriptMap = new HashMap<>();
    private String entityName = "";

    private ItemStack itemStack;

    public ScriptedItem(JsonObject jsonObject) {
        itemStack = createItemStack(jsonObject);

        getString(jsonObject, "entityName", string -> entityName = string);

        for (EventType eventType : EventType.values()) {
            String eventString = "EVENT." + eventType.name();
            if (!jsonObject.has(eventString) || !jsonObject.get(eventString).isJsonArray()) continue;
            scriptMap.put(eventType, Script.parseScript(jsonObject.getAsJsonArray(eventString)));
        }
    }

    private static ItemStack createItemStack(JsonObject jsonObject) {
        ItemStack itemStack = new ItemStack(Material.valueOf(getString(jsonObject, "type", "")), JsonUtils.getInt(jsonObject, "amount", 1));
        ItemMeta itemMeta = itemStack.getItemMeta();
        if (itemMeta == null) return itemStack;
        getString(jsonObject, "name", itemMeta::setDisplayName);

        if (jsonObject.has("lore")) {
            List<String> lore = new ArrayList<>();
            jsonObject.getAsJsonArray("lore").forEach(jsonElement -> lore.add(jsonElement.getAsString()));
            itemMeta.setLore(lore);
        }

        if (jsonObject.has("potion") && itemMeta instanceof PotionMeta) {
            JsonObject potionObject = jsonObject.getAsJsonObject("potion");
            potionObject.entrySet().forEach(stringJsonElementEntry -> {
                String key = stringJsonElementEntry.getKey();
                JsonObject currentObject = stringJsonElementEntry.getValue().getAsJsonObject();
                PotionEffectType potionEffectType = PotionEffectType.getByName(key);
                if (potionEffectType == null) return;
                int duration = JsonUtils.getInt(currentObject, "duration", 0);
                int amplifier = JsonUtils.getInt(currentObject, "amplifier", 0);
                PotionMeta potionMeta = (PotionMeta) itemMeta;
                potionMeta.addCustomEffect(new PotionEffect(potionEffectType, duration, amplifier), true);
            });
        }

        if (jsonObject.has("uses") && itemMeta instanceof Damageable) {
            int uses = jsonObject.getAsJsonPrimitive("uses").getAsInt();
            Damageable damageable = (Damageable) itemMeta;
            damageable.setDamage(itemStack.getType().getMaxDurability() - uses);
        }

        itemStack.setItemMeta(itemMeta);
        return itemStack;
    }

    public boolean execute(EventType eventType, Entity entity, Location location) {
        if (!scriptMap.containsKey(eventType)) return false;
        scriptMap.get(eventType).execute(new RunnableScriptEvent(eventType, entity, location));
        return true;
    }

    public ItemStack getItemStack() {
        return itemStack;
    }

    public String getEntityName() {
        return entityName;
    }
}
