package net.Chipperfluff.chipi.world.gen;

import net.minecraft.block.Blocks;
import net.minecraft.block.entity.StructureBlockBlockEntity;
import net.minecraft.block.enums.StructureBlockMode;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.structure.StructurePlacementData;
import net.minecraft.structure.StructureTemplate;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import java.util.Optional;

public abstract class ChipiStructure {

    protected final Identifier id;
    protected final int deltaX;
    protected final int deltaY;
    protected final int deltaZ;

    protected ChipiStructure(Identifier id, int deltaX, int deltaY, int deltaZ) {
        this.id = id;
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        this.deltaZ = deltaZ;
    }

    public BlockPos getSize(ServerWorld world) {
        Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
        if (opt.isEmpty()) return BlockPos.ORIGIN;
        Vec3i size = opt.get().getSize();
        return new BlockPos(size.getX(), size.getY(), size.getZ());
    }

    public void placeAt(ServerWorld world, BlockPos structureOrigin) {
        Optional<StructureTemplate> opt = world.getStructureTemplateManager().getTemplate(id);
        if (opt.isEmpty()) {
            System.out.println("[CHIPI] Missing structure: " + id);
            return;
        }

        BlockPos origin = structureOrigin.add(deltaX, deltaY, deltaZ);
        opt.get().place(world, origin, origin, new StructurePlacementData(), world.getRandom(), 2);
    }

    public void placeCommand(ServerWorld world, BlockPos structureOrigin, boolean marker) {
        placeAt(world, structureOrigin);
        if (!marker) return;

        BlockPos origin = structureOrigin.add(deltaX, deltaY, deltaZ);
        world.setBlockState(origin, Blocks.STRUCTURE_BLOCK.getDefaultState(), 3);

        if (world.getBlockEntity(origin) instanceof StructureBlockBlockEntity be) {
            be.setMode(StructureBlockMode.SAVE);
            be.setTemplateName(id);
            be.setSize(getSize(world));
            be.setIgnoreEntities(false);
            be.setShowAir(true);
            be.setShowBoundingBox(true);
            be.markDirty();
        }
    }

    public BlockPos localToWorld(BlockPos structureOrigin, BlockPos localPos) {
        return structureOrigin.add(
            deltaX + localPos.getX(),
            deltaY + localPos.getY(),
            deltaZ + localPos.getZ()
        );
    }

    public BlockPos worldToLocal(BlockPos structureOrigin, BlockPos worldPos) {
        return new BlockPos(
            worldPos.getX() - structureOrigin.getX() - deltaX,
            worldPos.getY() - structureOrigin.getY() - deltaY,
            worldPos.getZ() - structureOrigin.getZ() - deltaZ
        );
    }
}
