import { world, system, MolangVariableMap } from "@minecraft/server";

const eligibleBlocks = ["minecraft:pale_oak_log", "minecraft:pale_oak_wood", "minecraft:tuff", "minecraft:stone"];
const particleName = "gs_ce:creaking_eye";
const intervalTime = 200;
const biomeTag = "pale_garden";
const edgeOffset = 0.03;

function spawnParticlesAtVisibleBlocks(player, visibleBlocks) {
    visibleBlocks.forEach(({ position, molangVariables }) => {
        try {
            const centeredPosition = {
                x: position.x + 0.5 + (molangVariables["variable.gs_ce_block_face_x"] || 0) * edgeOffset,
                y: position.y + 0.5 + (molangVariables["variable.gs_ce_block_face_y"] || 0) * edgeOffset,
                z: position.z + 0.5 + (molangVariables["variable.gs_ce_block_face_z"] || 0) * edgeOffset,
            };
            const molang = new MolangVariableMap();
            for (const [key, value] of Object.entries(molangVariables)) {
                molang.setFloat(key, value);
            }
            player.dimension.spawnParticle(particleName, centeredPosition, molang);
        } catch (error) {}
    });
}

function getVisibleHorizontalBlocksWithMolang(player, radius = 16) {
    const position = player.location;
    const dimension = player.dimension;
    const visibleBlocks = [];
    const spawnChance = Math.random() * 0.05 + 0.1;

    for (let dx = -radius; dx <= radius; dx++) {
        for (let dy = -radius; dy <= radius; dy++) {
            for (let dz = -radius; dz <= radius; dz++) {
                const blockPos = {
                    x: Math.floor(position.x + dx),
                    y: Math.floor(position.y + dy),
                    z: Math.floor(position.z + dz),
                };
                const block = dimension.getBlock(blockPos);
                if (block && isBlockEligible(block.typeId) && Math.random() < spawnChance) {
                    const molangVariables = getVisibleHorizontalFaceAndDirection(blockPos, dimension);
                    if (molangVariables) {
                        visibleBlocks.push({ position: blockPos, molangVariables });
                    }
                }
            }
        }
    }
    return visibleBlocks;
}

function isBlockEligible(blockType) {
    const randomIndex = Math.floor(Math.random() * eligibleBlocks.length);
    return blockType === eligibleBlocks[randomIndex];
}

function getVisibleHorizontalFaceAndDirection(block, dimension) {
    const directions = [
        { x: 1, y: 0, z: 0, molang: { "variable.gs_ce_block_face_x": 1, "variable.gs_ce_block_face_y": 0, "variable.gs_ce_block_face_z": 0 } },
        { x: -1, y: 0, z: 0, molang: { "variable.gs_ce_block_face_x": -1, "variable.gs_ce_block_face_y": 0, "variable.gs_ce_block_face_z": 0 } },
        { x: 0, y: 0, z: 1, molang: { "variable.gs_ce_block_face_x": 0, "variable.gs_ce_block_face_y": 0, "variable.gs_ce_block_face_z": 1 } },
        { x: 0, y: 0, z: -1, molang: { "variable.gs_ce_block_face_x": 0, "variable.gs_ce_block_face_y": 0, "variable.gs_ce_block_face_z": -1 } }
    ];
    for (let i = directions.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [directions[i], directions[j]] = [directions[j], directions[i]];
    }
    for (const direction of directions) {
        const neighborPos = {
            x: block.x + direction.x,
            y: block.y + direction.y,
            z: block.z + direction.z,
        };
        const neighborBlock = dimension.getBlock(neighborPos);
        if (!neighborBlock || neighborBlock.typeId === "minecraft:air") {
            return direction.molang;
        }
    }
    return null;
}

system.runInterval(() => {
    world.getPlayers().forEach((player) => {
        if (player.hasTag(biomeTag)) {
            const visibleBlocks = getVisibleHorizontalBlocksWithMolang(player);
            if (visibleBlocks.length > 0) {
                spawnParticlesAtVisibleBlocks(player, visibleBlocks);
            }
        }
    });
}, intervalTime);
