/*
 *   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 com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.bausystem.utils.NMSWrapper;
import de.steamwar.core.Core;
import de.steamwar.inventory.SWItem;
import lombok.Getter;
import lombok.ToString;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;

import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;

@ToString
@Getter
public class BlockBoundingBox {

    private static List<String> randomPlayerHead = new ArrayList<>();
    private static Random random = new Random();

    static {
        randomPlayerHead.add("zOnlyKroks");
        randomPlayerHead.add("YoyoNow");
        randomPlayerHead.add("Konstruktix");
        randomPlayerHead.add("Merling03");
        randomPlayerHead.add("Lord_Loading");
        /*
        randomPlayerHead.add(UUID.fromString("1623d4b1-b21c-41d3-93c2-eee2845b8497"));
        randomPlayerHead.add(UUID.fromString("f75632be-e3ec-4069-9bec-d13ac6891177"));
        randomPlayerHead.add(UUID.fromString("80382970-424b-4299-9296-d956beab9e7b"));
        randomPlayerHead.add(UUID.fromString("f395ce89-096d-48e9-b796-a2d88722c22b"));
        randomPlayerHead.add(UUID.fromString("db516394-d999-4b77-8d13-73cceec77dfe"));
         */
    }

    public static List<BlockBoundingBox> elements = new ArrayList<>();

    public BlockData blockData;
    public List<Cuboid> cuboidList;
    private double volume;
    public SWItem swItem;

    public Consumer<BaseBlock> blockConsumer = null;

    public BlockBoundingBox(BlockData blockData, List<Cuboid> cuboidList, SWItem swItem) {
        this.blockData = blockData;
        this.cuboidList = cuboidList;
        this.swItem = swItem;
        volume = cuboidList.stream().mapToDouble(Cuboid::volume).sum();
        elements.add(this);
    }

    public BlockBoundingBox(BlockData blockData, List<Cuboid> cuboidList, SWItem swItem, Consumer<BaseBlock> blockConsumer) {
        this.blockData = blockData;
        this.cuboidList = cuboidList;
        this.swItem = swItem;
        volume = cuboidList.stream().mapToDouble(Cuboid::volume).sum();
        elements.add(this);
        this.blockConsumer = blockConsumer;
    }

    public double volume() {
        return volume;
    }

    static {
        addPixel(Material.AIR.createBlockData(), 0, 0, 0, 0, 0, 0, null);
        // addPixel(Material.COBWEB.createBlockData(), 0, 0, 0, 0, 0, 0, createItem("LAUFBAU_BLOCK_COBWEB", Material.COBWEB));
        addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null);

        addPixel(NMSWrapper.impl.pathMaterial().createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", NMSWrapper.impl.pathMaterial()));
        addPixel(Material.SOUL_SAND.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));

        Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
        cocoaNorth.setAge(2);
        cocoaNorth.setFacing(BlockFace.NORTH);
        addPixel(cocoaNorth, 4, 3, 1, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_NORTH"));

        Cocoa cocoaSouth = (Cocoa) Material.COCOA.createBlockData();
        cocoaSouth.setAge(2);
        cocoaSouth.setFacing(BlockFace.SOUTH);
        addPixel(cocoaSouth, 4, 3, 7, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_SOUTH"));

        Cocoa cocoaWest = (Cocoa) Material.COCOA.createBlockData();
        cocoaWest.setAge(2);
        cocoaWest.setFacing(BlockFace.WEST);
        addPixel(cocoaWest, 1, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_WEST"));

        Cocoa cocoaEast = (Cocoa) Material.COCOA.createBlockData();
        cocoaEast.setAge(2);
        cocoaEast.setFacing(BlockFace.EAST);
        addPixel(cocoaEast, 7, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_EAST"));

        TurtleEgg singleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
        singleTurtleEgg.setEggs(1);
        singleTurtleEgg.setHatch(0);
        addPixel(singleTurtleEgg, 4, 0, 3, 9, 7, 9, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_1"));

        TurtleEgg doubleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
        doubleTurtleEgg.setEggs(2);
        doubleTurtleEgg.setHatch(0);
        addPixel(doubleTurtleEgg, 1, 0, 1, 14, 7, 14, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_2"));

        addPixel(Material.CHEST.createBlockData(), 1, 0, 1, 14, 14, 14, createItem("LAUFBAU_BLOCK_CHEST", Material.CHEST));

        Snow snowLayers8 = (Snow) Material.SNOW.createBlockData();
        snowLayers8.setLayers(8);
        addPixel(snowLayers8, 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_8"));

        Directional headNorth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
        headNorth.setFacing(BlockFace.NORTH);
        addPixel(headNorth, 4, 4, 8, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_NORTH"), BlockBoundingBox::randomPlayerHead);

        Directional headSouth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
        headSouth.setFacing(BlockFace.SOUTH);
        addPixel(headSouth, 4, 4, 0, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_SOUTH"), BlockBoundingBox::randomPlayerHead);

        Directional headWest = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
        headWest.setFacing(BlockFace.WEST);
        addPixel(headWest, 8, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_WEST"), BlockBoundingBox::randomPlayerHead);

        Directional headEast = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
        headEast.setFacing(BlockFace.EAST);
        addPixel(headEast, 0, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_EAST"), BlockBoundingBox::randomPlayerHead);

        Snow snowLayers7 = (Snow) Material.SNOW.createBlockData();
        snowLayers7.setLayers(7);
        addPixel(snowLayers7, 0, 0, 0, 16, 12, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_7"));

        Snow snowLayers6 = (Snow) Material.SNOW.createBlockData();
        snowLayers6.setLayers(6);
        addPixel(snowLayers6, 0, 0, 0, 16, 10, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_6"));

        addPixel(Material.STONECUTTER.createBlockData(), 0, 0, 0, 16, 9, 16, createItem("LAUFBAU_BLOCK_STONECUTTER", Material.STONECUTTER));

        addPixel(Material.PLAYER_HEAD.createBlockData(), 4, 0, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_HEAD", Material.PLAYER_HEAD), BlockBoundingBox::randomPlayerHead);

        addPixel(Material.CAKE.createBlockData(), 1, 0, 1, 14, 8, 14, createItem("LAUFBAU_BLOCK_CAKE", Material.CAKE));

        Slab bottomSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
        bottomSlab.setType(Slab.Type.BOTTOM);
        addPixel(bottomSlab, 0, 0, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_BOTTOM"));

        Slab topSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
        topSlab.setType(Slab.Type.TOP);
        addPixel(topSlab, 0, 8, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_TOP"));

        SeaPickle quadSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
        quadSeaPickle.setWaterlogged(false);
        quadSeaPickle.setPickles(4);
        addPixel(quadSeaPickle, 2, 0, 2, 12, 7, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_4"));

        Campfire campfire = (Campfire) Material.CAMPFIRE.createBlockData();
        campfire.setSignalFire(false);
        campfire.setLit(false);
        addPixel(campfire, 0, 0, 0, 16, 7, 16, createItem("LAUFBAU_BLOCK_CAMPFIRE", Material.CAMPFIRE));

        SeaPickle trippleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
        trippleSeaPickle.setWaterlogged(false);
        trippleSeaPickle.setPickles(3);
        addPixel(trippleSeaPickle, 2, 0, 2, 12, 6, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_3"));

        SeaPickle doubleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
        doubleSeaPickle.setWaterlogged(false);
        doubleSeaPickle.setPickles(2);
        addPixel(doubleSeaPickle, 3, 0, 3, 10, 6, 10, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_2"));

        SeaPickle singleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
        singleSeaPickle.setWaterlogged(false);
        singleSeaPickle.setPickles(1);
        addPixel(singleSeaPickle, 6, 0, 6, 4, 6, 4, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_1"));

        addPixel(Material.FLOWER_POT.createBlockData(), 5, 0, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_FLOWER_POT", Material.FLOWER_POT));

        Snow snowLayers3 = (Snow) Material.SNOW.createBlockData();
        snowLayers3.setLayers(3);
        addPixel(snowLayers3, 0, 0, 0, 16, 4, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_3"));

        TrapDoor bottomTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        bottomTrapDoor.setHalf(Bisected.Half.BOTTOM);
        addPixel(bottomTrapDoor, 0, 0, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_BOTTOM"));

        TrapDoor topTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        topTrapDoor.setHalf(Bisected.Half.TOP);
        addPixel(topTrapDoor, 0, 13, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_TOP"));

        Snow snowLayers2 = (Snow) Material.SNOW.createBlockData();
        snowLayers2.setLayers(2);
        addPixel(snowLayers2, 0, 0, 0, 16, 2, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_2"));

        addPixel(Material.LILY_PAD.createBlockData(), 1, 0, 1, 14, 1.5, 14, createItem("LAUFBAU_BLOCK_LILY_PAD", Material.LILY_PAD));
        addPixel(Material.WHITE_CARPET.createBlockData(), 0, 0, 0, 16, 1, 16, createItem("LAUFBAU_BLOCK_WHITE_CARPET", Material.WHITE_CARPET));

        Directional endRodBottomTop = (Directional) Material.END_ROD.createBlockData();
        endRodBottomTop.setFacing(BlockFace.UP);
        addPixel(endRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));

        Directional endRodNorthSouth = (Directional) Material.END_ROD.createBlockData();
        endRodNorthSouth.setFacing(BlockFace.NORTH);
        addPixel(endRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));

        Directional endRodEastWest = (Directional) Material.END_ROD.createBlockData();
        endRodEastWest.setFacing(BlockFace.EAST);
        addPixel(endRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));

        if (Core.getVersion() >= 19) {
            Directional lightningRodBottomTop = (Directional) Material.LIGHTNING_ROD.createBlockData();
            lightningRodBottomTop.setFacing(BlockFace.UP);
            addPixel(lightningRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));

            Directional lightningRodNorthSouth = (Directional) Material.LIGHTNING_ROD.createBlockData();
            lightningRodNorthSouth.setFacing(BlockFace.NORTH);
            addPixel(lightningRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));

            Directional lightningRodEastWest = (Directional) Material.LIGHTNING_ROD.createBlockData();
            lightningRodEastWest.setFacing(BlockFace.EAST);
            addPixel(lightningRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
        }

        Waterlogged conduit = (Waterlogged) Material.CONDUIT.createBlockData();
        conduit.setWaterlogged(false);
        addPixel(conduit, 5, 5, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_CONDUIT", Material.CONDUIT));

        TrapDoor northTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        northTrapDoor.setFacing(BlockFace.NORTH);
        northTrapDoor.setOpen(true);
        addPixel(northTrapDoor, 0, 0, 13, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_NORTH", "LAUFBAU_OPEN"));

        TrapDoor southTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        southTrapDoor.setFacing(BlockFace.SOUTH);
        southTrapDoor.setOpen(true);
        addPixel(southTrapDoor, 0, 0, 0, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_SOUTH", "LAUFBAU_OPEN"));

        TrapDoor westTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        westTrapDoor.setFacing(BlockFace.WEST);
        westTrapDoor.setOpen(true);
        addPixel(westTrapDoor, 13, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_WEST", "LAUFBAU_OPEN"));

        TrapDoor eastTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
        eastTrapDoor.setFacing(BlockFace.EAST);
        eastTrapDoor.setOpen(true);
        addPixel(eastTrapDoor, 0, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_EAST", "LAUFBAU_OPEN"));
    }

    private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem) {
        new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem);
    }

    private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem, Consumer<BaseBlock> blockConsumer) {
        new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem, blockConsumer);
    }

    @SuppressWarnings("deprecation")
    private static void randomPlayerHead(BaseBlock block) {
        if (block instanceof SkullBlock) {
            SkullBlock skullBlock = (SkullBlock) block;
            skullBlock.setOwner(randomPlayerHead.get(random.nextInt(randomPlayerHead.size())).toString());
        }
    }
}
