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

const structurePools = {
    "fire": {
        "dead_end": { weight: 3, structures: ["fire_dead_end"] },
        "one_to_one": { weight: 4, structures: ["fire_one-one", "fire_one-one_str"] },
        "corner": { weight: 5, structures: ["fire_corner_L", "fire_corner_R"] },
        "t_junction": { weight: 4, structures: ["fire_T-J", "fire_T-J_2", "fire_T-J_3", "fire_T-J_str_1", "fire_T-J_str_2"] },
        "big": { weight: 4, structures: ["fire_jigsaw_Entrance", "fire_jigsaw_Entrance-2", "fire_jigsaw_Entrance-3", "fire_jigsaw_Entrance-4"] },
        "cap": { weight: 1, structures: ["fire_cap"] }
    },
    "ice": {
        "dead_end": { weight: 5, structures: ["ice_dead_end"] },
        "one_to_one": { weight: 4, structures: ["ice_one-one", "ice_one-one_str"] },
        "corner": { weight: 4, structures: ["ice_corner_L", "ice_corner_R"] },
        "t_junction": { weight: 3, structures: ["ice_T-J_1", "ice_T-J_2", "ice_T-J_3", "ice_T-J_str_1", "ice_T-J_str_2"] },
        "big": { weight: 3, structures: ["ice_jigsaw_1"] },
        "cap": { weight: 1, structures: ["ice_cap"] }
    },
    "mushroom": {
        "dead_end": { weight: 5, structures: ["mush_dead_end", "mush_dead_end_str"] },
        "one_to_one": { weight: 4, structures: ["mush_one-one", "mush_one-one_str"] },
        "corner": { weight: 3, structures: ["mush_corner_L", "mush_corner_R"] },
        "t_junction": { weight: 4, structures: ["mush_T-J", "mush_T-J_2", "mush_T-J_3", "mush_T-J_1_str"] },
        "cap": { weight: 1, structures: ["mush_cap"] }
    }
};

const structureSizes = {
    "fire_jigsaw_Entrance": { x: 62, y: 31, z: 62 },
    "fire_jigsaw_Entrance-2": { x: 62, y: 31, z: 62 },
    "fire_jigsaw_Entrance-3": { x: 62, y: 31, z: 31 },
    "fire_jigsaw_Entrance-4": { x: 62, y: 31, z: 31 },
    "ice_jigsaw_1": { x: 62, y: 31, z: 31 },
    "default": { x: 31, y: 31, z: 31 }
};

const facingToRotation = {
    "east": StructureRotation.None,
    "south": StructureRotation.Rotate90,
    "west": StructureRotation.Rotate180,
    "north": StructureRotation.Rotate270
};

const directionOffsets = {
    [StructureRotation.None]: { x: 1, y: -16, z: -16 },
    [StructureRotation.Rotate90]: { x: -15, y: -16, z: 1 },
    [StructureRotation.Rotate180]: { x: -31, y: -16, z: -15 },
    [StructureRotation.Rotate270]: { x: -16, y: -16, z: -31 }
};

const capDirectionOffsets = {
    [StructureRotation.None]: { x: 1, y: -16, z: -16 },
    [StructureRotation.Rotate90]: { x: -16, y: -16, z: 1 },
    [StructureRotation.Rotate180]: { x: -4, y: -16, z: -16 },
    [StructureRotation.Rotate270]: { x: -16, y: -16, z: -4 }
};

const CHUNK_SIZE = 31;
const occupiedChunks = new Map();

function getChunkCoord(coord) {
    return Math.floor(coord / CHUNK_SIZE);
}

function getTouchedChunkKeys(box) {
    const keys = [];
    const xStart = getChunkCoord(box.x1);
    const xEnd = getChunkCoord(box.x2);
    const zStart = getChunkCoord(box.z1);
    const zEnd = getChunkCoord(box.z2);

    for (let x = xStart; x <= xEnd; x++) {
        for (let z = zStart; z <= zEnd; z++) {
            keys.push(`${x},${z}`);
        }
    }

    return keys;
}

function markOccupied(box) {
    for (const key of getTouchedChunkKeys(box)) {
        if (!occupiedChunks.has(key)) {
            occupiedChunks.set(key, []);
        }
        occupiedChunks.get(key).push(box);
    }
}

function isOverlapping(box) {
    for (const key of getTouchedChunkKeys(box)) {
        const boxes = occupiedChunks.get(key);
        if (!boxes) continue;

        for (const other of boxes) {
            if (
                box.x1 <= other.x2 && box.x2 >= other.x1 &&
                box.y1 <= other.y2 && box.y2 >= other.y1 &&
                box.z1 <= other.z2 && box.z2 >= other.z1
            ) {
                return true;
            }
        }
    }

    return false;
}

function getBoundingBox(spawnLoc, size, rotation) {
    const rotatedSize = (size.x !== size.z && 
        (rotation === StructureRotation.Rotate90 || rotation === StructureRotation.Rotate270))
        ? { x: size.z, y: size.y, z: size.x }
        : size;

    return {
        x1: spawnLoc.x,
        y1: spawnLoc.y,
        z1: spawnLoc.z,
        x2: spawnLoc.x + rotatedSize.x - 1,
        y2: spawnLoc.y + rotatedSize.y - 1,
        z2: spawnLoc.z + rotatedSize.z - 1
    };
}

function getBiomeFromJigsaw(block) {
    const id = block.typeId;
    if (id.includes("fire")) return "fire";
    if (id.includes("ice")) return "ice";
    return "mushroom";
}

function getRandomConnectionType(biome, exclude = []) {
    const biomePool = structurePools[biome];
    if (!biomePool) return null;

    const filtered = Object.entries(biomePool)
        .filter(([type]) => !exclude.includes(type));

    const totalWeight = filtered.reduce((sum, [_, data]) => sum + data.weight, 0);
    let r = Math.random() * totalWeight;

    for (const [type, data] of filtered) {
        if (r < data.weight) return type;
        r -= data.weight;
    }

    return null;
}

function getRandomStructure(biome, type) {
    const list = structurePools?.[biome]?.[type]?.structures;
    return list?.length ? list[Math.floor(Math.random() * list.length)] : null;
}

function tryPlaceStructure(biome, connectionType, spawn, rotation) {
    const structure = getRandomStructure(biome, connectionType);
    if (!structure) return false;

    const size = structureSizes[structure] ?? structureSizes["default"];
    const box = getBoundingBox(spawn, size, rotation);

    if (!isOverlapping(box)) {
        markOccupied(box);
        const structureName = `gs_cb:${structure}`;
        const dimension = world.getDimension("overworld");
        try {
            world.structureManager.place(
            structureName,
            dimension,
            spawn,
            {
                rotation: rotation,
                includeEntities: true,
                integrity: 1,
                mirror: false
            }
        );
        } catch(error) {}
        
        return true;
    }

    return false;
}

world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => {
    blockComponentRegistry.registerCustomComponent("gs_cb:custom_jigsaw", {
        onTick: ({ block }) => {
            const playersNearby = block.dimension.getEntities({
                location: block.location,
                maxDistance: 64,
                type: "minecraft:player"
            });
            if (playersNearby.length === 0) return;

            const anchor = block.location;
            const facing = block.permutation.getState("minecraft:facing_direction");
            const rotation = facingToRotation[facing];
            if (rotation === undefined) return;

            const biome = getBiomeFromJigsaw(block);
            const offset = directionOffsets[rotation];
            if (!offset) return;

            const spawn = {
                x: anchor.x + offset.x,
                y: anchor.y + offset.y,
                z: anchor.z + offset.z
            };

            const connectionType = getRandomConnectionType(biome, ["cap"]);
            if (tryPlaceStructure(biome, connectionType, spawn, rotation)) {
                block.setType("minecraft:air");
                return;
            }

            if (connectionType === "big") {
                const fallbackType = getRandomConnectionType(biome, ["big", "cap"]);
                if (tryPlaceStructure(biome, fallbackType, spawn, rotation)) {
                    block.setType("minecraft:air");
                    return;
                }
            }

            const capStructure = getRandomStructure(biome, "cap");
            if (capStructure) {
                const capOffset = capDirectionOffsets[rotation];
                const capSpawn = {
                    x: anchor.x + capOffset.x,
                    y: anchor.y + capOffset.y,
                    z: anchor.z + capOffset.z
                };
                
                const structureName = `gs_cb:${capStructure}`;
                const dimension = world.getDimension("overworld");
                try {
                    world.structureManager.place(
                    structureName,
                    dimension,
                    capSpawn,
                    {
                        rotation: rotation,
                        includeEntities: true,
                        integrity: 1,
                        mirror: false
                    }
                );
                } catch(error) {}
            }

            block.setType("minecraft:air");
        }
    });

    blockComponentRegistry.registerCustomComponent("gs_cb:custom_jigsaw_2", {
        onTick: ({ block }) => {
            const playersNearby = block.dimension.getEntities({
                location: block.location,
                maxDistance: 64,
                type: "minecraft:player"
            });
            if (playersNearby.length === 0) return;

            const anchorLoc = block.location;
            const facing = block.permutation.getState("minecraft:facing_direction");
            const rotation = facingToRotation[facing];
            if (rotation === undefined) return;

            const structureId = block.typeId;
            const offset = directionOffsets[rotation];
            if (!offset) return;

            const spawnLoc = {
                x: anchorLoc.x + offset.x,
                y: anchorLoc.y + offset.y + 1,
                z: anchorLoc.z + offset.z
            };

            const dimension = world.getDimension("overworld");
            try {
                world.structureManager.place(
                structureId,
                dimension,
                spawnLoc,
                {
                    rotation: rotation,
                    includeEntities: true,
                    integrity: 1,
                    mirror: false
                }
            );
            } catch(error) {}
            
            block.setType("minecraft:air");
        }
    });
});