/*
 *   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.bausystem.features.detonator.storage;

import de.steamwar.bausystem.SWUtils;
import lombok.Getter;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.function.IntFunction;

public class ItemStorage implements DetonatorStorage {

    private static final NamespacedKey DETO_KEY = SWUtils.getNamespaceKey("deto");
    private static final NamespacedKey SLOT_KEY = SWUtils.getNamespaceKey("slots");
    private static final IntFunction<NamespacedKey> DETOLOCATION_BUILDER = integer -> SWUtils.getNamespaceKey("deto_loc_" + integer);
    @Getter
    private final Player p;
    private final List<Location> locs;
    private int slot;
    private ItemStack itemStack;

    public ItemStorage(Player p) {
        this.p = p;
        if (isDetonator(p.getInventory().getItemInMainHand())) {
            slot = p.getInventory().getHeldItemSlot();
            itemStack = p.getInventory().getItemInMainHand();
        } else {
            ItemStack[] inv = p.getInventory().getContents();
            for (int i = 0; i < inv.length; i++) {
                if (isDetonator(inv[i])) {
                    slot = i;
                    itemStack = inv[i];
                    break;
                }
            }
        }
        locs = read();
    }

    public static ItemStack setDetonator(ItemStack item) {
        ItemMeta meta = item.getItemMeta();
        if (meta == null) {
            return item;
        }
        PersistentDataContainer dataContainer = meta.getPersistentDataContainer();
        dataContainer.set(DETO_KEY, PersistentDataType.BYTE, (byte) 1);
        dataContainer.set(SLOT_KEY, PersistentDataType.INTEGER, 0);
        item.setItemMeta(meta);
        return item;
    }

    public static boolean isDetonator(ItemStack item) {
        if (item == null) {
            return false;
        }
        ItemMeta meta = item.getItemMeta();
        if (meta == null) {
            return false;
        }
        PersistentDataContainer container = meta.getPersistentDataContainer();
        return container.has(DETO_KEY, PersistentDataType.BYTE) && container.has(SLOT_KEY, PersistentDataType.INTEGER);
    }

    @Override
    public void addLocation(Location location) {
        locs.add(location);
    }

    @Override
    public List<Location> getLocations() {
        return locs;
    }

    @Override
    public void removeLocation(Location location) {
        locs.remove(location);
    }

    @Override
    public void clear() {
        internalClear();
        locs.clear();
        apply();
    }

    @Override
    public void write() {
        write(locs);
    }

    @Override
    public Player getPlayer() {
        return p;
    }

    private List<Location> read() {
        List<Location> tempLocs = new LinkedList<>();

        if (itemStack == null) {
            return Collections.emptyList();
        }
        ItemMeta meta = itemStack.getItemMeta();
        if (meta == null) {
            return Collections.emptyList();
        }
        PersistentDataContainer container = meta.getPersistentDataContainer();

        int length = length();
        for (int i = 0; i < length; i++) {
            NamespacedKey key = DETOLOCATION_BUILDER.apply(i);
            int[] loc = container.get(key, PersistentDataType.INTEGER_ARRAY);
            tempLocs.add(new Location(p.getWorld(), loc[0], loc[1], loc[2]));
        }

        return tempLocs;
    }

    private int length() {
        ItemMeta meta = itemStack.getItemMeta();
        PersistentDataContainer container = meta.getPersistentDataContainer();
        return container.get(SLOT_KEY, PersistentDataType.INTEGER);
    }

    private void internalClear() {
        ItemMeta meta = itemStack.getItemMeta();
        PersistentDataContainer container = meta.getPersistentDataContainer();

        int length = length();
        for (int i = 0; i < length; i++) {
            NamespacedKey key = DETOLOCATION_BUILDER.apply(i);
            container.remove(key);
        }

        container.set(SLOT_KEY, PersistentDataType.INTEGER, 0);

        itemStack.setItemMeta(meta);
    }

    private void write(List<Location> locs) {
        internalClear();
        ItemMeta meta = itemStack.getItemMeta();
        PersistentDataContainer container = meta.getPersistentDataContainer();

        int i = 0;
        for (Location loc : locs) {
            NamespacedKey key = DETOLOCATION_BUILDER.apply(i);
            int[] slotLoc = new int[]{
                    loc.getBlockX(),
                    loc.getBlockY(),
                    loc.getBlockZ()
            };
            container.set(key, PersistentDataType.INTEGER_ARRAY, slotLoc);
            i++;
        }

        container.set(SLOT_KEY, PersistentDataType.INTEGER, i);

        itemStack.setItemMeta(meta);
        apply();
    }

    private void apply() {
        p.getInventory().setItem(slot, itemStack);
    }
}
