import * as Minecraft from "@minecraft/server"

const replaceBlocks = [
    {
        replace: "minecraft:grass_path",
        with: ["aria_ah:dirt"],
        maxLevel: 1
    },
    {
        replace: "minecraft:melon_block",
        with: ["aria_ah:melon"],
        maxLevel: 1
    },
    {
        replace: "minecraft:pumpkin",
        with: ["aria_ah:pumpkin"],
        maxLevel: 1
    },
    {
        replace: "minecraft:acacia_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:birch_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:cherry_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:dark_oak_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:jungle_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:mangrove_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:oak_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:spruce_log",
        with: ["aria_ah:dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },

    {
        replace: "minecraft:stripped_acacia_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_birch_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_cherry_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_dark_oak_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_jungle_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_mangrove_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_oak_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },
    {
        replace: "minecraft:stripped_spruce_log",
        with: ["aria_ah:stripped_dark_log"],
        maxLevel: 30,
        sound: "aria_ah.fog.wood"
    },

    {
        replace: "minecraft:acacia_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:birch_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:cherry_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:dark_oak_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:jungle_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:mangrove_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:oak_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "minecraft:spruce_leaves",
        with: ["aria_ah:dark_leaves"],
        maxLevel: 30,
        sound: "aria_ah.fog.plant"
    },
    {
        replace: "aria_ah:dead_bamboo",
        with: ["aria_ah:dark_bamboo"],
        maxLevel: 19
    },

    {
        replace: "minecraft:leaf_litter",
        with: [
            "aria_ah:leaves",
            "aria_ah:stones"
        ],
        maxLevel: 1
    }
]
const replacePlantBlocks = [
    {
        with: [
            "aria_ah:allium"
        ],
        replace: "minecraft:allium"
    },
    {
        with: [
            "aria_ah:azure_bluet"
        ],
        replace: "minecraft:azure_bluet"
    },
    {
        with: [
            "aria_ah:blue_orchid"
        ],
        replace: "minecraft:blue_orchid"
    },
    {
        with: [
            "aria_ah:cornflower"
        ],
        replace: "minecraft:cornflower"
    },
    {
        with: [
            "aria_ah:dandelion"
        ],
        replace: "minecraft:dandelion"
    },
    {
        with: [
            "aria_ah:deadbush"
        ],
        replace: "minecraft:deadbush"
    },
    {
        with: [
            "aria_ah:fern"
        ],
        replace: "minecraft:fern"
    },
    {
        with: [
            "aria_ah:large_fern"
        ],
        replace: "minecraft:large_fern"
    },
    {
        with: [
            "aria_ah:lilac"
        ],
        replace: "minecraft:lilac"
    },
    {
        with: [
            "aria_ah:lily_of_the_valley"
        ],
        replace: "minecraft:lily_of_the_valley"
    },
    {
        with: [
            "aria_ah:oxeye_daisy"
        ],
        replace: "minecraft:oxeye_daisy"
    },
    {
        with: [
            "aria_ah:peony"
        ],
        replace: "minecraft:peony"
    },
    {
        with: [
            "aria_ah:pink_petals"
        ],
        replace: "minecraft:pink_petals"
    },
    {
        with: [
            "aria_ah:pitcher_plant"
        ],
        replace: "minecraft:pitcher_plant"
    },
    {
        with: [
            "aria_ah:poppy"
        ],
        replace: "minecraft:poppy"
    },
    {
        with: [
            "aria_ah:rose_bush"
        ],
        replace: "minecraft:rose_bush"
    },
    {
        with: [
            "aria_ah:short_grass"
        ],
        replace: "minecraft:short_grass",
        maxRandomState: 2
    },
    {
        with: [
            "aria_ah:sunflower"
        ],
        replace: "minecraft:sunflower"
    },
    {
        with: [
            "aria_ah:tall_grass"
        ],
        replace: "minecraft:tall_grass"
    },
    {
        replace: "minecraft:firefly_bush",
        with: ["aria_ah:firefly_bush"]
    },
    {
        with: [
            "aria_ah:torchflower"
        ],
        replace: "minecraft:torchflower"
    },
    {
        with: [
            "aria_ah:tulip_orange"
        ],
        replace: "minecraft:orange_tulip"
    },
    {
        with: [
            "aria_ah:tulip_pink"
        ],
        replace: "minecraft:pink_tulip"
    },
    {
        with: [
            "aria_ah:tulip_red"
        ],
        replace: "minecraft:red_tulip"
    },
    {
        with: [
            "aria_ah:tulip_white"
        ],
        replace: "minecraft:white_tulip"
    },
    
    {
        replace: "minecraft:wildflowers",
        with: [
            "aria_ah:leaves",
            "aria_ah:stones"
        ]
    },
    
    {
        with: [
            "aria_ah:red_mushroom"
        ],
        replace: "minecraft:red_mushroom"
    },
    {
        with: [
            "aria_ah:brown_mushroom"
        ],
        replace: "minecraft:brown_mushroom"
    },

    {
        replace: "minecraft:cave_vines",
        with: ["aria_ah:glow_berries"]
    }
]
const replaceCrops = [
    {
        replace: "minecraft:beetroot",
        with: ["aria_ah:beetroot_seeds"]
    },
    {
        replace: "minecraft:carrots",
        with: ["aria_ah:carrot_seeds"]
    },
    {
        replace: "minecraft:melon_stem",
        with: ["aria_ah:melon_seeds"]
    },
    {
        replace: "minecraft:pitcher_pod",
        with: ["aria_ah:pitcher_pod"]
    },
    {
        replace: "minecraft:potatoes",
        with: ["aria_ah:potato"]
    },
    {
        replace: "minecraft:pumpkin_stem",
        with: ["aria_ah:pumpkin_seeds"]
    },
    {
        replace: "minecraft:sweet_berry_bush",
        with: ["aria_ah:sweet_berries"]
    },
    {
        replace: "minecraft:torchflower_crop",
        with: ["aria_ah:torchflower_seeds"]
    },
    {
        replace: "minecraft:wheat",
        with: ["aria_ah:wheat_seeds"]
    }
]
const replaceDifficultBlocks = [
    {
        replace: "minecraft:farmland",
        with: ["aria_ah:farmland"],
        maxLevel: 1
    },
    {
        with: [
            "aria_ah:grass"
        ],
        replace: "minecraft:grass_block",
        maxLevel: 3
    },
    {
        replace: "minecraft:dirt",
        with: ["aria_ah:dirt"],
        chance: 0.7,
        maxLevel: 1
    },
    {
        replace: "minecraft:podzol",
        with: ["aria_ah:podzol"],
        chance: 0.7,
        maxLevel: 1
    },
    {
        replace: "minecraft:coarse_dirt",
        with: ["aria_ah:dirt"],
        chance: 0.7,
        maxLevel: 1
    }
]
const directions = [
    {
        block: (block, i) => {
            if (block?.north) {
                return { block: block.north(i), direction: "north", opposite: "south" }
            }
        }
    },
    {
        block: (block, i) => {
            if (block?.south) {
                return { block: block.south(i), direction: "south", opposite: "north" }
            }
        }
    },
    {
        block: (block, i) => {
            if (block?.east) {
                return { block: block.east(i), direction: "east", opposite: "west" }
            }
        }
    },
    {
        block: (block, i) => {
            if (block?.west) {
                return { block: block.west(i), direction: "west", opposite: "east" }
            }
        }
    },
    {
        block: (block, i) => {
            if (block?.above) {
                return { block: block.above(i), direction: "above", opposite: "below" }
            }
        }
    },
    {
        block: (block, i) => {
            if (block?.below) {
                return { block: block.below(i), direction: "below", opposite: "above" }
            }
        }
    }
]
const cardinalDirections = [
    {
        block: (block, i) => {
            if (block?.north) {
                return block.north(i)
            }
        },
        direction: "north"
    },
    {
        block: (block, i) => {
            if (block?.south) {
                return block.south(i)
            }
        },
        direction: "south"
    },
    {
        block: (block, i) => {
            if (block?.east) {
                return block.east(i)
            }
        },
        direction: "east"
    },
    {
        block: (block, i) => {
            if (block?.west) {
                return block.west(i)
            }
        },
        direction: "west"
    }
]


Minecraft.system.runInterval(() => {
    if (!Minecraft.world.scoreboard.getObjective("aria_ah.biome_horror").getScore("fog_env_fill")) {
        return
    }

    for (const fogEntity of Minecraft.world.getDimension("overworld").getEntities({ type: "aria_ah:dark_fog" })) {
        if (!fogEntity.isValid) {
            continue
        }

        for (const blockPos of fogEntity.dimension.getBlocks(
            new Minecraft.BlockVolume(
                {
                    x: fogEntity.location.x - 1,
                    y: fogEntity.location.y - 1,
                    z: fogEntity.location.z - 2
                },
                {
                    x: fogEntity.location.x + 1,
                    y: fogEntity.location.y + 1,
                    z: fogEntity.location.z + 2
                }
            ),
            {
                includeTypes: replaceDifficultBlocks.map((block) => block.replace).concat(replaceBlocks.map((block) => block.replace)).concat(replacePlantBlocks.map((block) => block.replace))
            },
            true
        ).getBlockLocationIterator()) {
            const block = fogEntity.dimension.getBlock(blockPos)
            const above = block.above()
            const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == block.typeId)
            const replaceCrop = replaceCrops.find((crop) => crop.replace == above.typeId)

            if (above.typeId == "minecraft:bamboo") {
                replaceBlockWithBamboo(above)
            } else if (replaceCrop && difficultBlock) {
                const growth = above.permutation.getState("growth") ?? 0
                above.setType(replaceCrop.with[Math.floor(Math.random() * replaceCrop.with.length)])
                above.setPermutation(
                    above.permutation.withState("aria_ah:growth", growth)
                )
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
            } else if (difficultBlock) {
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
                block.setPermutation(
                    block.permutation.withState("aria_ah:one", difficultBlock.maxLevel)
                )
            }
        }
        for (const blockPos of fogEntity.dimension.getBlocks(
            new Minecraft.BlockVolume(
                {
                    x: fogEntity.location.x - 2,
                    y: fogEntity.location.y - 1,
                    z: fogEntity.location.z - 1
                },
                {
                    x: fogEntity.location.x + 2,
                    y: fogEntity.location.y + 1,
                    z: fogEntity.location.z + 1
                }
            ),
            {
                includeTypes: replaceDifficultBlocks.map((block) => block.replace).concat(replaceBlocks.map((block) => block.replace)).concat(replacePlantBlocks.map((block) => block.replace))
            },
            true
        ).getBlockLocationIterator()) {
            const block = fogEntity.dimension.getBlock(blockPos)
            const above = block.above()
            const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == block.typeId)
            const replaceCrop = replaceCrops.find((crop) => crop.replace == above.typeId)

            if (above.typeId == "minecraft:bamboo") {
                replaceBlockWithBamboo(above)
            } else if (replaceCrop && difficultBlock) {
                const growth = above.permutation.getState("growth") ?? 0
                above.setType(replaceCrop.with[Math.floor(Math.random() * replaceCrop.with.length)])
                above.setPermutation(
                    above.permutation.withState("aria_ah:growth", growth)
                )
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
            } else if (difficultBlock) {
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
                block.setPermutation(
                    block.permutation.withState("aria_ah:one", difficultBlock.maxLevel)
                )
            }
        }

        for (const replacePlant of replacePlantBlocks) {
            let foundAny = false
            foundAny += fogEntity.runCommand(`fill ~-2 ~-1 ~-1 ~2 ~1 ~1 ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]}[${replacePlant.maxRandomState ? `"aria_ah:type"=${Math.floor(Math.random() * replacePlant.maxRandomState)}` : ""}] replace ${replacePlant.replace}`).successCount
            foundAny += fogEntity.runCommand(`fill ~-1 ~-1 ~-2 ~1 ~1 ~2 ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]}[${replacePlant.maxRandomState ? `"aria_ah:type"=${Math.floor(Math.random() * replacePlant.maxRandomState)}` : ""}] replace ${replacePlant.replace}`).successCount

            if (foundAny) {
                fogEntity.dimension.playSound("aria_ah.fog.plant", fogEntity.location, { volume: 3 })
            }
        }
        for (const replaceBlock of replaceBlocks) {
            fogEntity.runCommand(`fill ~-2 ~-1 ~-1 ~2 ~1 ~1 ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${replaceBlock.maxLevel}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`)
            fogEntity.runCommand(`fill ~-1 ~-1 ~-2 ~1 ~1 ~2 ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${replaceBlock.maxLevel}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`)
        }

        replaceLightSources(fogEntity.location, fogEntity.dimension, 3, 2, -1)
    }
}, 20)

Minecraft.system.runInterval(() => {
    const protectTamed = Minecraft.world.scoreboard.getObjective("aria_ah.general").getScore("protect_tamed")

    if (protectTamed) {
        for (const tamedEntity of Minecraft.world.getDimension("overworld").getEntities({ excludeTags: ["aria_ah_tamed"] })) {
            if (tamedEntity.getComponent(Minecraft.EntityComponentTypes.IsTamed)) {
                tamedEntity.addTag("aria_ah_tamed")
            }
        }
    } else {
        for (const tamedEntity of Minecraft.world.getDimension("overworld").getEntities({ tags: ["aria_ah_tamed"] })) {
            tamedEntity.removeTag("aria_ah_tamed")
        }
    }
}, 40)

Minecraft.system.beforeEvents.startup.subscribe((event) => {
    event.blockComponentRegistry.registerCustomComponent("aria_ah:dark_spread", {
        onTick: (event) => {
            let level = (10 * (event.block.permutation.getState("aria_ah:ten") ?? 0) + event.block.permutation.getState("aria_ah:one")) - 1
            for (const direction of directions) {
                /** @type {Minecraft.Block} */
                let { block, direction: dir } = direction.block(event.block)
                const replaceWith = replaceBlocks.find((replace) => replace.replace == block?.typeId) || replaceDifficultBlocks.find((replace) => replace.replace == block?.typeId)

                if (replaceWith) {
                    if (Math.random() > (replaceWith?.chance ?? 1)) {
                        continue
                    }

                    const oldPermutation = block.permutation
                    const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == block.typeId)
                    block.setType(replaceWith.with[Math.floor(Math.random() * replaceWith.with.length)])

                    if ((block.typeId == "aria_ah:dark_log" || block.typeId == "aria_ah:dark_leaves") && !(event.block.typeId == "aria_ah:log" || event.block.typeId == "aria_ah:leaves")) {
                        level = 30
                    } else if (difficultBlock?.maxLevel) {
                        const above = block.above()
                        const replacePlant = replacePlantBlocks.find((plant) => plant.replace == above.typeId)
                        const replaceCrop = replaceCrops.find((crop) => crop.replace == above.typeId)

                        if (above?.typeId == "minecraft:bamboo") {
                            replaceBlockWithBamboo(above)
                        } else if (replacePlant) {
                            above.setType(replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)])

                            block.dimension.playSound("aria_ah.fog.plant", block.center(), { volume: 3 })
                        } else if (replaceCrop) {
                            const growth = above.permutation.getState("growth") ?? 0
                            above.setType(replaceCrop.with[Math.floor(Math.random() * replaceCrop.with.length)])
                            above.setPermutation(
                                above.permutation.withState("aria_ah:growth", growth)
                            )
                            block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
                        }
                    }

                    let permutation = block.permutation
                    if (replaceWith.replace == "aria_ah:dead_bamboo") {
                        permutation = permutation.withState("aria_ah:bamboo_leaf_size", oldPermutation.getState("aria_ah:bamboo_leaf_size"))
                        permutation = permutation.withState("aria_ah:bamboo_stalk_thickness", oldPermutation.getState("aria_ah:bamboo_stalk_thickness"))
                        permutation = permutation.withState("aria_ah:age_bit", oldPermutation.getState("aria_ah:age_bit"))
                    } {
                        if (!isNaN(block.permutation.getState("aria_ah:ten")) && level >= 10) {
                            permutation = permutation.withState("aria_ah:ten", Math.min(Math.floor(level / 10), 1))
                        }
                        permutation = permutation.withState("aria_ah:one", Math.min(level % 10, replaceWith?.maxLevel ?? 0))
                    }

                    block.setPermutation(permutation)

                    if (replaceWith.sound) {
                        block.dimension.playSound(replaceWith.sound, block.center(), { volume: 3 })
                    }
                } else if (block?.typeId == "minecraft:vine") {
                    replaceVines(block)
                } else if (block?.isValid && block?.isAir && (dir == "above" || dir == "below")) {
                    for (const direction of cardinalDirections) {
                        /** @type {Minecraft.Block} */
                        let sideBlock = direction.block(block)
                        const replaceWith = replaceBlocks.find((replace) => replace.replace == sideBlock?.typeId) || replaceDifficultBlocks.find((replace) => replace.replace == sideBlock?.typeId)
                        
                        if (replaceWith) {
                            if (Math.random() > (replaceWith?.chance ?? 1)) {
                                continue
                            }

                            const oldPermutation = sideBlock.permutation
                            const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == sideBlock.typeId)
                            sideBlock.setType(replaceWith.with[Math.floor(Math.random() * replaceWith.with.length)])

                            if ((sideBlock.typeId == "aria_ah:dark_log" || sideBlock.typeId == "aria_ah:dark_leaves") && !(block.typeId == "aria_ah:log" || block.typeId == "aria_ah:leaves")) {
                                level = 30
                            } else if (difficultBlock?.maxLevel) {
                                const above = sideBlock.above()
                                const replacePlant = replacePlantBlocks.find((plant) => plant.replace == above.typeId)

                                if (above?.typeId == "minecraft:bamboo") {
                                    replaceBlockWithBamboo(above)
                                } else if (replacePlant) {
                                    above.setType(replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)])

                                    sideBlock.dimension.playSound("aria_ah.fog.plant", sideBlock.center(), { volume: 3 })
                                }
                            }

                            let permutation = sideBlock.permutation
                            if (replaceWith.replace == "aria_ah:dead_bamboo") {
                                permutation = permutation.withState("aria_ah:bamboo_leaf_size", oldPermutation.getState("aria_ah:bamboo_leaf_size"))
                                permutation = permutation.withState("aria_ah:bamboo_stalk_thickness", oldPermutation.getState("aria_ah:bamboo_stalk_thickness"))
                                permutation = permutation.withState("aria_ah:age_bit", oldPermutation.getState("aria_ah:age_bit"))
                            } {
                                if (!isNaN(sideBlock.permutation.getState("aria_ah:ten")) && level >= 10) {
                                    permutation = permutation.withState("aria_ah:ten", Math.min(Math.floor(level / 10), 1))
                                }
                                permutation = permutation.withState("aria_ah:one", Math.min(level % 10, replaceWith?.maxLevel ?? 0))
                            }

                            sideBlock.setPermutation(permutation)

                            if (replaceWith.sound) {
                                sideBlock.dimension.playSound(replaceWith.sound, sideBlock.center(), { volume: 3 })
                            }
                        }
                    }
                }
            }

            if (event.block.permutation.getState("aria_ah:ten")) {
                event.block.setPermutation(event.block.permutation.withState("aria_ah:ten", 0))
            }
            if (event.block.permutation.getState("aria_ah:one")) {
                event.block.setPermutation(event.block.permutation.withState("aria_ah:one", 0))
            }
        }
    })
})

Minecraft.world.afterEvents.itemUse.subscribe((event) => {
    if (event.itemStack.typeId == "aria_ah:bone_meal") {
        const block = event.source.getBlockFromViewDirection({ maxDistance: 8 })?.block
        if (!block) {
            return
        }
        let foundAny = false

        for (const replacePlant of replacePlantBlocks) {
            foundAny = event.source.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run fill ~-2 ~-1 ~-1 ~2 ~1 ~1 ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]} replace ${replacePlant.replace}`).successCount
            foundAny = event.source.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run fill ~-1 ~-1 ~-2 ~1 ~1 ~2 ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]} replace ${replacePlant.replace}`).successCount

            if (foundAny) {
                block.dimension.playSound("aria_ah.fog.plant", block.center(), { volume: 3 })
            }
        }
        for (const replaceBlock of replaceBlocks) {
            foundAny = event.source.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run fill ~-2 ~-1 ~-1 ~2 ~1 ~1 ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${replaceBlock.maxLevel}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`).successCount
            foundAny = event.source.runCommand(`execute positioned ${block.x} ${block.y} ${block.z} run fill ~-1 ~-1 ~-2 ~1 ~1 ~2 ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${replaceBlock.maxLevel}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`).successCount
        }

        if (foundAny) {
            const equippable = event.source.getComponent(Minecraft.EntityComponentTypes.Equippable)
            const handItem = equippable?.getEquipment(Minecraft.EquipmentSlot.Mainhand)

            if (event.source.getGameMode() != Minecraft.GameMode.Creative) {
                if (handItem.amount > 1) {
                    handItem.amount--
                    equippable?.setEquipment(Minecraft.EquipmentSlot.Mainhand, handItem)
                } else {
                    equippable?.setEquipment(Minecraft.EquipmentSlot.Mainhand)
                }
            }
        }
    }
})

Minecraft.system.afterEvents.scriptEventReceive.subscribe((event) => {
    if (event.id == "aria_ah:create_horror_biome" && event.sourceType == Minecraft.ScriptEventSource.Entity) {
        const [radius, height, start] = event.message.split(" ")
        const source = event.sourceEntity
        if (isNaN(radius) || isNaN(height) || isNaN(start)) {
            return
        }

        for (const replacePlant of replacePlantBlocks) {
            let foundAny = false
            foundAny = source.runCommand(`fill ~-${radius} ~${start} ~-${radius} ~${radius} ~${Number(height) + Number(start)} ~${radius} ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]} replace ${replacePlant.replace}`).successCount
            foundAny = source.runCommand(`fill ~-${radius} ~${start} ~-${radius} ~${radius} ~${Number(height) + Number(start)} ~${radius} ${replacePlant.with[Math.floor(Math.random() * replacePlant.with.length)]} replace ${replacePlant.replace}`).successCount

            if (foundAny) {
                source.dimension.playSound("aria_ah.fog.plant", source.location, { volume: 3 })
            }
        }

        for (const blockPos of source.dimension.getBlocks(
            new Minecraft.BlockVolume(
                {
                    x: source.location.x - Number(radius),
                    y: source.location.y + Number(start),
                    z: source.location.z - Number(radius)
                },
                {
                    x: source.location.x + Number(radius),
                    y: source.location.y + Number(height) + Number(start),
                    z: source.location.z + Number(radius)
                }
            ),
            {
                includeTypes: replaceDifficultBlocks.map((block) => block.replace).concat(replaceBlocks.map((block) => block.replace)).concat(replacePlantBlocks.map((block) => block.replace))
            },
            true
        ).getBlockLocationIterator()) {
            const block = source.dimension.getBlock(blockPos)
            const above = block.above()
            const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == block.typeId)
            const replaceCrop = replaceCrops.find((crop) => crop.replace == above.typeId)

            if (above.typeId == "minecraft:bamboo") {
                replaceBlockWithBamboo(above)
            } else if (replaceCrop && difficultBlock) {
                const growth = above.permutation.getState("growth") ?? 0
                above.setType(replaceCrop.with[Math.floor(Math.random() * replaceCrop.with.length)])
                above.setPermutation(
                    above.permutation.withState("aria_ah:growth", growth)
                )
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
            } else if (difficultBlock) {
                block.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])
                block.setPermutation(
                    block.permutation.withState("aria_ah:one", difficultBlock.maxLevel)
                )
            }
        }

        for (const replaceBlock of replaceBlocks) {
            source.runCommand(`fill ~-${radius} ~${start} ~-${radius} ~${radius} ~${Number(height) + Number(start)} ~${radius} ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${Math.floor(replaceBlock.maxLevel / 10)}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`)
            source.runCommand(`fill ~-${radius} ~${start} ~-${radius} ~${radius} ~${Number(height) + Number(start)} ~${radius} ${replaceBlock.with[Math.floor(Math.random() * replaceBlock.with.length)]}[${replaceBlock.maxLevel > 9 ? `"aria_ah:ten"=${Math.floor(replaceBlock.maxLevel / 10)}, ` : ""}"aria_ah:one"=${replaceBlock.maxLevel % 10}] replace ${replaceBlock.replace}`)
        }
    } else if (event.id == "aria_ah:replace_light_sources" && event.sourceType == Minecraft.ScriptEventSource.Entity) {
        const [radius, height, start] = event.message.split(" ")
        const source = event.sourceEntity
        if (isNaN(radius) || isNaN(height) || isNaN(start)) {
            return
        }
        replaceLightSources(source.location, source.dimension, Number(radius), Number(height), Number(start))
    }
})


function replaceBlockWithBamboo(above) {
    let startHightDelta = 0
    let lowestBlockFound = false
    let endHightDelta = 0
    let highestBlockFound = false

    while (!lowestBlockFound) {
        if (above.above(startHightDelta - 1).typeId == "minecraft:bamboo") {
            startHightDelta--
        } else {
            lowestBlockFound = true
        }
    }
    while (!highestBlockFound) {
        if (above.above(endHightDelta + 1).typeId == "minecraft:bamboo") {
            endHightDelta++
        } else {
            highestBlockFound = true
        }
    }

    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="no_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="no_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="no_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="no_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="small_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="small_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="small_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="small_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="large_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="large_leaves", "bamboo_stalk_thickness"="thin", "age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false] replace minecraft:bamboo["bamboo_leaf_size"="large_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y + startHightDelta} ${above.z} ${above.x} ${above.y + endHightDelta} ${above.z} aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true] replace minecraft:bamboo["bamboo_leaf_size"="large_leaves", "bamboo_stalk_thickness"="thick", "age_bit"=true]`)

    const below = above.below(startHightDelta + 1)
    const difficultBlock = replaceDifficultBlocks.find((replace) => replace.replace == below.typeId)
    if (!difficultBlock) {
        return
    }
    below.setType(difficultBlock.with[Math.floor(Math.random() * difficultBlock.with.length)])

    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="no_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="small_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thin", "aria_ah:age_bit"=true]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=false]`)
    above.dimension.runCommand(`fill ${above.x} ${above.y} ${above.z} ${above.x} ${above.y} ${above.z} aria_ah:dark_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true, "aria_ah:ten"=1, "aria_ah:one"=9] replace aria_ah:dead_bamboo["aria_ah:bamboo_leaf_size"="large_leaves", "aria_ah:bamboo_stalk_thickness"="thick", "aria_ah:age_bit"=true]`)
}

/**
 * 
 * @param {Minecraft.Block} block 
 */
function replaceVines(block) {
    let startHightDelta = 0
    let lowestBlockFound = false
    let endHightDelta = 0
    let highestBlockFound = false

    while (!lowestBlockFound) {
        const newBlock = block.above(startHightDelta - 1)
        const vineState = newBlock.permutation.getState("vine_direction_bits")
        if (newBlock.typeId == "minecraft:vine") {
            newBlock.setType("aria_ah:vine")
            newBlock.setPermutation(
                newBlock.permutation.withState("aria_ah:vine_direction_bits", vineState).withState("aria_ah:initialized", true)
            )
            startHightDelta--
        } else {
            lowestBlockFound = true
        }
    }
    while (!highestBlockFound) {
        const newBlock = block.above(endHightDelta + 1)
        const vineState = newBlock.permutation.getState("vine_direction_bits")
        if (newBlock.typeId == "minecraft:vine") {
            newBlock.setType("aria_ah:vine")
            newBlock.setPermutation(
                newBlock.permutation.withState("aria_ah:vine_direction_bits", vineState).withState("aria_ah:initialized", true)
            )
            endHightDelta++
        } else {
            highestBlockFound = true
        }
    }
    const vineState = block.permutation.getState("vine_direction_bits")
    block.setType("aria_ah:vine")
    block.setPermutation(
        block.permutation.withState("aria_ah:vine_direction_bits", vineState).withState("aria_ah:initialized", true)
    )
}

function replaceLightSources(location, dimension, radius, height, start) {
    if (!location || !dimension || isNaN(radius) || isNaN(height) || isNaN(start)) {
        return
    }
    radius = Number(radius)
    height = Number(height)
    start = Number(start)

    for (const blockPos of dimension.getBlocks(
        new Minecraft.BlockVolume(
            { x: location.x - radius, y: location.y + start, z: location.z - radius },
            { x: location.x + radius, y: location.y + start + height, z: location.z + radius }
        ),
        {
            includeTypes: [
                "minecraft:torch",
                "minecraft:lantern",
                "minecraft:campfire",

                "minecraft:candle",
                "minecraft:white_candle",
                "minecraft:light_gray_candle",
                "minecraft:gray_candle",
                "minecraft:black_candle",
                "minecraft:brown_candle",
                "minecraft:red_candle",
                "minecraft:orange_candle",
                "minecraft:yellow_candle",
                "minecraft:lime_candle",
                "minecraft:green_candle",
                "minecraft:cyan_candle",
                "minecraft:light_blue_candle",
                "minecraft:blue_candle",
                "minecraft:purple_candle",
                "minecraft:magenta_candle",
                "minecraft:pink_candle",

                "minecraft:lit_pumpkin",
                "minecraft:fire"
            ]
        },
        true
    ).getBlockLocationIterator()) {
        const block = dimension.getBlock(blockPos)
        if (!block?.isValid) {
            continue
        }

        if (block.typeId == "minecraft:torch") {
            const blockFace = {
                north: "south",
                south: "north",
                east: "west",
                west: "east"
            }[block.permutation.getState("torch_facing_direction")] || "up"
            
            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.setType("aria_ah:torch")
            block.setPermutation(block.permutation.withState("minecraft:block_face", blockFace))
            block.dimension.playSound("aria_ah.light_off", block.center())
        } else if (block.typeId == "minecraft:lantern") {
            const hanging = block.permutation.getState("hanging")

            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.setType("aria_ah:lantern")
            block.setPermutation(block.permutation.withState("minecraft:block_face", hanging ? "down" : "up"))
            block.dimension.playSound("aria_ah.light_off", block.center())
        } else if (block.typeId == "minecraft:campfire") {
            const rotation = block.permutation.getState("minecraft:cardinal_direction")

            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.setType("aria_ah:campfire")
            block.setPermutation(block.permutation.withState("minecraft:cardinal_direction", rotation))
            block.dimension.playSound("aria_ah.light_off", block.center())
        } else if (block.typeId.endsWith("candle")) {
            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.dimension.runCommand(`setblock ${block.x} ${block.y} ${block.z} air destroy`)
            block.dimension.playSound("aria_ah.light_off", block.center())
        } else if (block.typeId == "minecraft:lit_pumpkin") {
            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.setType("aria_ah:pumpkin")
            block.dimension.playSound("aria_ah.light_off", block.center())
        } else if (block.typeId == "minecraft:fire") {
            block.dimension.spawnParticle("aria_ah:light_off", block.center())
            block.setType("minecraft:air")
            block.dimension.playSound("aria_ah.light_off", block.center())
        }
    }
}
