/*
 *   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.slaves.laufbau;

import de.steamwar.bausystem.BauSystem;
import de.steamwar.core.SWPlayer;
import de.steamwar.inventory.SWItem;
import de.steamwar.sql.UserConfig;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.meta.ItemMeta;
import yapion.hierarchy.output.StreamOutput;
import yapion.hierarchy.types.YAPIONObject;
import yapion.parser.YAPIONParser;
import yapion.parser.options.StreamOptions;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

@UtilityClass
public class LaufbauUtils {

    public static class LaufbauComponent implements SWPlayer.Component {

        private YAPIONObject yapionObject = new YAPIONObject();

        @Override
        @SneakyThrows
        public void onMount(SWPlayer player) {
            String config = UserConfig.getConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau");
            if (config == null) {
                return;
            }
            byte[] bytes = Base64.getDecoder().decode(config);
            @Cleanup GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(bytes));
            yapionObject = new YAPIONParser(gzipInputStream, new StreamOptions().stopOnStreamEnd(true)).parse().result();
        }

        @Override
        @SneakyThrows
        public void onUnmount(SWPlayer player) {
            if (yapionObject.isEmpty()) {
                UserConfig.removePlayerConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau");
                return;
            }
            @Cleanup ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            @Cleanup GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream);
            yapionObject.toYAPION(new StreamOutput(gzipOutputStream)).close();
            UserConfig.updatePlayerConfig(player.getPlayer().getUniqueId(), "bausystem-laufbau", Base64.getEncoder().encodeToString(byteArrayOutputStream.toByteArray()));
        }
    }

    public static Cuboid pixelCuboid(double pixelX, double pixelY, double pixelZ, double pixelDX, double pixelDY, double pixelDZ) {
        return new Cuboid(pixelToBlock(pixelX), pixelToBlock(pixelY), pixelToBlock(pixelZ), pixelToBlock(pixelDX), pixelToBlock(pixelDY), pixelToBlock(pixelDZ));
    }

    public static double pixelToBlock(double pixel) {
        return 1.0 / 16 * pixel;
    }

    public static SWItem createItem(String name, Material material, String... lore) {
        return new SWItem(material, name, Arrays.asList(lore), false, clickType -> {
        });
    }

    public static SWItem translateItem(SWItem item, Player p) {
        ItemMeta itemMeta = item.getItemMeta();
        List<String> lore = new ArrayList<>();
        if (itemMeta.getLore() != null) {
            lore = itemMeta.getLore().stream().map(s -> BauSystem.MESSAGE.parse(s, p)).collect(Collectors.toList());
        }
        return new SWItem(item.getItemStack().getType(), BauSystem.MESSAGE.parse(itemMeta.getDisplayName(), p), lore, false, clickType -> {
        });
    }

    public static String identifier(BlockBoundingBox bb) {
        if (bb.getSwItem() == null) {
            return null;
        }
        SWItem item = bb.getSwItem();
        ItemMeta itemMeta = item.getItemMeta();
        List<String> lore = new ArrayList<>();
        if (itemMeta.getLore() != null) {
            lore = itemMeta.getLore()
                    .stream()
                    .map(s -> s.substring(8))
                    .collect(Collectors.toList());
        }
        String name = itemMeta.getDisplayName().substring(14);
        return name + "[" + String.join(",", lore) + "]";
    }

    @SneakyThrows
    public static boolean isDeactivated(Player p, BlockBoundingBox bb) {
        if (bb.getSwItem() == null) {
            return false;
        }
        String identifier = identifier(bb);
        return SWPlayer.of(p).getComponentOrDefault(LaufbauComponent.class, LaufbauComponent::new).yapionObject.containsKey(identifier);
    }

    @SneakyThrows
    public static void toggle(Player p, BlockBoundingBox bb) {
        if (bb.getSwItem() == null) {
            return;
        }
        String identifier = identifier(bb);
        YAPIONObject yapionObject = SWPlayer.of(p).getComponentOrDefault(LaufbauComponent.class, LaufbauComponent::new).yapionObject;
        if (yapionObject.containsKey(identifier)) {
            yapionObject.remove(identifier);
        } else {
            yapionObject.put(identifier, new YAPIONObject());
        }
    }
}
