import { EquipmentSlot, GameMode, ItemStack, system, world } from "@minecraft/server";

const maxGrowth = {
    "aria_ah:wheat_seeds": 7,
    "aria_ah:carrot": 3,
    "aria_ah:potato": 7,
    "aria_ah:beetroot_seeds": 3,
    "aria_ah:sweet_berries": 3,
    "aria_ah:torchflower_seeds": 2,
    "aria_ah:pumpkin_seeds": 7,
    "aria_ah:melon_seeds": 7
};
const maxDoubleGrowth = {
    "aria_ah:pitcher_pod": {
        max: 4,
        top_min: 2
    }
};
const growthState = "aria_ah:growth";
const directions = [
    { block: (block, i) => block.north(i), direction: "north", opposite: "south" },
    { block: (block, i) => block.south(i), direction: "south", opposite: "north" },
    { block: (block, i) => block.east(i), direction: "east", opposite: "west" },
    { block: (block, i) => block.west(i), direction: "west", opposite: "east" }
]
const convertedFlowers = [
    "aria_ah:flower6",
    "aria_ah:flower7",
    "aria_ah:flower8",
    "aria_ah:flower9",
    "aria_ah:flower10",
    "aria_ah:flower11",
    "aria_ah:flower12",
    "aria_ah:flower13",
    "aria_ah:flower14",
    "aria_ah:flower15",
    "aria_ah:flower16",
    "aria_ah:flower17"
]
const convertedFlowersLarge = [
    "aria_ah:flower1",
    "aria_ah:flower2",
    "aria_ah:flower3",
    "aria_ah:flower4",
    "aria_ah:flower5"
]
const convertedFlowersSmall = [
    "aria_ah:flower18"
]

/** @type {import("@minecraft/server").BlockCustomComponent} */
const CropGrowthBlockComponent = {
    onRandomTick({ block }) {
        const growthChance = (world.getTimeOfDay() < 12610) ? 0.25 : 0.5;
        if (Math.random() > growthChance) return;

        const growth = block.permutation.getState(growthState);
        block.setPermutation(block.permutation.withState(growthState, growth + 1));
    },

    onPlayerInteract({ block, dimension, player }) {
        if (!player) return;

        const equippable = player.getComponent("minecraft:equippable");
        if (!equippable) return;

        const mainhand = equippable.getEquipmentSlot(EquipmentSlot.Mainhand);
        if (!mainhand.hasItem() || mainhand.typeId !== "aria_ah:bone_meal") return;

        if (player.getGameMode() === GameMode.Creative) {
            if (block.typeId === "aria_ah:torchflower_seeds") {
                block.setType("aria_ah:torchflower");
            } else {
                block.setPermutation(block.permutation.withState(growthState, maxGrowth[block.typeId]));
            }
        } else {
            let growth = block.permutation.getState(growthState);
            growth += Math.max((Math.floor(Math.random() * (maxGrowth[block.typeId] - growth))), 1);

            if (block.typeId === "aria_ah:torchflower_seeds" && growth >= 2) {
                block.setType("aria_ah:torchflower");
            } else {
                block.setPermutation(block.permutation.withState(growthState, growth));

                if (mainhand.amount > 1) mainhand.amount--;
                else mainhand.setItem(undefined);
            }
        }

        const effectLocation = block.center();
        dimension.playSound("item.bone_meal.use", effectLocation);
        dimension.spawnParticle("minecraft:crop_growth_emitter", effectLocation);
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const SweetBerryBushBlockComponent = {
    onPlayerInteract({ block, dimension, player }) {
        block.dimension.spawnItem(new ItemStack("aria_ah:sweet_berries", Math.floor(Math.random() * 2) + (-2 + block.permutation.getState("aria_ah:growth"))), block.center());
    
        block.setPermutation(block.permutation.withState("aria_ah:growth", 1));
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const TallGrassBlockComponent = {
    beforeOnPlayerPlace({ block, player, cancel }) {
        const aboveBlock = block.above();

        if (!aboveBlock.isAir) {
            cancel = true;
            return;
        }
        
        system.run(() => {
            aboveBlock.setType(block.typeId);
            aboveBlock.setPermutation(block.permutation.withState("aria_ah:upper_block_bit", true));
        })
    },

    onPlayerBreak({ brokenBlockPermutation, block }) {
        if (brokenBlockPermutation.getState("aria_ah:upper_block_bit")) {
            block.dimension.runCommand(`setblock ${block.location.x} ${block.location.y - 1} ${block.location.z} air destroy`);
        }
    },

    onPlace({ block }) {
        if (!block.permutation.getState("aria_ah:upper_block_bit")) {
            const aboveBlock = block.above();
            aboveBlock.setType(block.typeId);
            aboveBlock.setPermutation(block.permutation.withState("aria_ah:upper_block_bit", true));
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const PetalsBlockComponent = {
    onPlayerInteract({ block, dimension, player }) {
        const equippable = player.getComponent("minecraft:equippable");
        if (!equippable) return;

        const mainhand = equippable.getEquipment(EquipmentSlot.Mainhand);
        const flowers = block.permutation.getState("aria_ah:flowers");
        
        if (mainhand?.typeId == "aria_ah:pink_petals" || mainhand?.typeId == "minecraft:bone_meal") {
            if (mainhand.typeId == "minecraft:bone_meal") {
                block.dimension.spawnParticle("minecraft:crop_growth_emitter", block.center());
            }

            if (flowers < 3) {
                block.setPermutation(block.permutation.withState("aria_ah:flowers", flowers + 1));
            } else {
                dimension.spawnItem(new ItemStack("aria_ah:pink_petals", 1), block.center());
            }

            if (player.getGameMode() !== GameMode.Creative) {
                if (mainhand.amount > 1) {
                    mainhand.amount--;
                    equippable.setEquipment(EquipmentSlot.Mainhand, mainhand);
                } else {
                    equippable.setEquipment(EquipmentSlot.Mainhand);
                }
            }
        }
    },

    onPlayerBreak({ dimension, player, brokenBlockPermutation, block }) {
        if (player.getGameMode() !== GameMode.Creative) {
            const flowers = brokenBlockPermutation.getState("aria_ah:flowers");
            dimension.spawnItem(new ItemStack("aria_ah:pink_petals", flowers + 1), block.center());
        }
    }
}

/** @type {import("@minecraft/server").BlockCustomComponent} */
const FullBlockCropBlockComponent = {
    onRandomTick({ block }) {
        if (block.permutation.getState("aria_ah:growth") < 7 || block.permutation.getState("aria_ah:connected")) {
            return;
        }

        const airBlock = findAirBlock(block);
        const airBlockType = airBlock?.block(block, 1);
        if (!airBlock) {
            return;
        }

        airBlockType.setType(block.typeId.replace("_stem", ""));
        block.setPermutation(block.permutation.withState("aria_ah:connected", true));
        block.setPermutation(block.permutation.withState("aria_ah:connected_side", airBlock.direction));
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const DoubleCropGrowthBlockComponent = {
    onRandomTick({ block }) {
        if (block.permutation.getState("aria_ah:upper_block_bit")) return;

        const growthChance = (world.getTimeOfDay() < 12610) ? 0.25 : 0.5;
        if (Math.random() > growthChance) return;

        const growth = (block.permutation.getState(growthState) + 1);

        if (growth >= maxDoubleGrowth[block.typeId].top_min) {
            const topBlock = block.above();
            if (!topBlock.isAir && topBlock.typeId !== block.typeId) return;
            else if (topBlock.typeId !== block.typeId) {
                topBlock.setType(block.typeId);
                topBlock.setPermutation(topBlock.permutation.withState(growthState, growth).withState("aria_ah:upper_block_bit", true));
            } else {
                topBlock.setPermutation(topBlock.permutation.withState(growthState, growth));
            }
        }

        block.setPermutation(block.permutation.withState(growthState, growth));
    },

    onPlayerInteract({ block, dimension, player }) {
        if (!player) return;

        const equippable = player.getComponent("minecraft:equippable");
        if (!equippable) return;

        const mainhand = equippable.getEquipmentSlot(EquipmentSlot.Mainhand);
        if (!mainhand.hasItem() || mainhand.typeId !== "minecraft:bone_meal") return;

        const growth = block.permutation.getState(growthState) + 1;
        if (block.permutation.getState("aria_ah:upper_block_bit")) {
            block.below().setPermutation(block.below().permutation.withState(growthState, growth));
        } else {
            if (growth >= maxDoubleGrowth[block.typeId].top_min) {
                const topBlock = block.above();
                if (!topBlock.isAir && topBlock.typeId !== block.typeId) return;
                else if (topBlock.typeId !== block.typeId) {
                    topBlock.setType(block.typeId);
                    topBlock.setPermutation(topBlock.permutation.withState(growthState, growth).withState("aria_ah:upper_block_bit", true));
                } else {
                    topBlock.setPermutation(topBlock.permutation.withState(growthState, growth));
                }
            }
        }
        block.setPermutation(block.permutation.withState(growthState, growth));

        if (player.getGameMode() !== GameMode.Creative) {
            if (mainhand.amount > 1) mainhand.amount--;
            else mainhand.setItem(undefined);
        }

        const effectLocation = block.center();
        dimension.playSound("item.bone_meal.use", effectLocation);
        dimension.spawnParticle("minecraft:crop_growth_emitter", effectLocation);
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const HangingCropBlockComponent = {
    onRandomTick({ block }) {
        if (block.isAir) return;

        const growthChance = 1 / 3;

        if (Math.random() > growthChance) {
            block.setPermutation(block.permutation.withState("aria_ah:has_berries", true));
        }

        if (block.permutation.getState("aria_ah:cropped") || block.permutation.getState("aria_ah:part") == "body" || !block.below().isAir || Math.random() > growthChance) return;

        block.setPermutation(block.permutation.withState("aria_ah:part", "body"));

        const age = (block.permutation.getState("aria_ah:growing_plant_age") ?? 0) + 1;
        const belowBlock = block.below();
        belowBlock.setType(block.typeId);
        belowBlock.setPermutation(block.permutation.withState("aria_ah:growing_plant_age", age));
        belowBlock.setPermutation(belowBlock.permutation.withState("aria_ah:part", "head"));

        if (age >= 15 || (age >= 2 && Math.random() < 0.2)) {
            belowBlock.setPermutation(belowBlock.permutation.withState("aria_ah:cropped", true));
        }
    },

    onPlayerBreak({ block, brokenBlockPermutation }) {
        const aboveBlock = block.above();
        
        if (aboveBlock.typeId === brokenBlockPermutation.type.id) {
            aboveBlock.setPermutation(aboveBlock.permutation.withState("aria_ah:part", "head"));
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const GlowBerriesBlockComponent = {
    onPlayerInteract({ block, dimension, player }) {
        if (block.permutation.getState("aria_ah:has_berries")) {
            block.dimension.spawnItem(new ItemStack("aria_ah:glow_berries", 1), block.center());
            block.setPermutation(block.permutation.withState("aria_ah:has_berries", false));
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const ConvertFlowerBlockComponent = {
    onRandomTick({ block }) {
        if (Math.random() > 0.66) {
            if (world.scoreboard.getObjective("aria_ah.general").getScore("vv_active")) {
                block.dimension.spawnParticle("aria_ah:plant_growth_vv", block.center())
            } else {
                block.dimension.spawnParticle("aria_ah:plant_growth", block.center());
            }

            block.dimension.playSound("item.bone_meal.use", block.center())
            block.setType(convertedFlowers[Math.floor(Math.random() * convertedFlowers.length)])
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const ConvertFlowerLargeBlockComponent = {
    onRandomTick({ block }) {
        if (Math.random() > 0.66 && !block.permutation.getState("aria_ah:upper_block_bit")) {
            const above = block.above()

            if (world.scoreboard.getObjective("aria_ah.general").getScore("vv_active")) {
                block.dimension.spawnParticle("aria_ah:plant_growth_vv", block.center())
            } else {
                block.dimension.spawnParticle("aria_ah:plant_growth", block.center());
            }

            block.dimension.playSound("item.bone_meal.use", block.center())
            above.setType("minecraft:air")
            block.setType(convertedFlowersLarge[Math.floor(Math.random() * convertedFlowersLarge.length)])
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const ConvertFlowerSmallBlockComponent = {
    onRandomTick({ block }) {
        if (Math.random() > 0.66) {
            if (world.scoreboard.getObjective("aria_ah.general").getScore("vv_active")) {
                block.dimension.spawnParticle("aria_ah:plant_growth_vv", block.center())
            } else {
                block.dimension.spawnParticle("aria_ah:plant_growth", block.center());
            }

            block.dimension.playSound("item.bone_meal.use", block.center())
            block.setType(convertedFlowersSmall[Math.floor(Math.random() * convertedFlowersSmall.length)])
        }
    }
};


/** @type {import("@minecraft/server").BlockCustomComponent} */
const BambooBlockComponent = {
    onRandomTick({ block }) {
        if (Math.random() > 0.66) {
            if (world.scoreboard.getObjective("aria_ah.general").getScore("vv_active")) {
                block.dimension.spawnParticle("aria_ah:plant_growth_vv", block.center())
            } else {
                block.dimension.spawnParticle("aria_ah:plant_growth", block.center());
            }
            
            block.dimension.playSound("item.bone_meal.use", block.center())
            block.setType(convertedFlowersSmall[Math.floor(Math.random() * convertedFlowersSmall.length)])
        }
    }
};

/** @type {import("@minecraft/server").BlockCustomComponent} */
const CaveVinesGrowthBlockComponent = {
    onPlayerInteract({ block, dimension, player }) {
        const equippable = player.getComponent("minecraft:equippable");
        if (!equippable) return;
        const handItem = equippable.getEquipment(EquipmentSlot.Mainhand)
        if (handItem?.typeId === "minecraft:bone_meal") {
            block.setPermutation(block.permutation.withState("aria_ah:has_berries", true));
            if (player.getGameMode() !== GameMode.Creative) {
                if (handItem.amount > 1) {
                    handItem.amount--;
                    equippable.setEquipment(EquipmentSlot.Mainhand, handItem);
                } else {
                    equippable.setEquipment(EquipmentSlot.Mainhand);
                }
            }
        }
    }
}

system.beforeEvents.startup.subscribe(({ blockComponentRegistry }) => {
    blockComponentRegistry.registerCustomComponent(
        "aria_ah:crop_growth",
        CropGrowthBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:sweet_berry_bush",
        SweetBerryBushBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:tall_grass",
        TallGrassBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:petals",
        PetalsBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:full_block_crop",
        FullBlockCropBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:double_crop_growth",
        DoubleCropGrowthBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:hanging_crop",
        HangingCropBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:glow_berries",
        GlowBerriesBlockComponent
    );

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:convert_flower",
        ConvertFlowerBlockComponent
    )

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:convert_flower_small",
        ConvertFlowerSmallBlockComponent
    )

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:convert_flower_large",
        ConvertFlowerLargeBlockComponent
    )

    blockComponentRegistry.registerCustomComponent(
        "aria_ah:cave_vines",
        CaveVinesGrowthBlockComponent
    )
});

world.afterEvents.playerBreakBlock.subscribe(({ block, brokenBlockPermutation }) => {
    if (!block.isValid) {
        return;
    }

    if (brokenBlockPermutation.type.id === "aria_ah:pumpkin" || brokenBlockPermutation.type.id === "aria_ah:melon") {
        for (const direction of directions) {
            const directedBlock = direction.block(block, 1);
            
            if (directedBlock.isValid && directedBlock.typeId === (brokenBlockPermutation.type.id + "_seeds") && directedBlock.permutation.getState("aria_ah:connected") && directedBlock.permutation.getState("aria_ah:connected_side") === direction.opposite) {
                directedBlock.setPermutation(directedBlock.permutation.withState("aria_ah:connected", false));
            }
        }
    } else if (block.below().typeId === "aria_ah:glow_berries") {
        let count = 1;

        while(true) {
            const belowBlock = block.below(count);
            count++;

            if (belowBlock.isValid && belowBlock.typeId === "aria_ah:glow_berries") {
                block.dimension.runCommand(`setblock ${belowBlock.location.x} ${belowBlock.location.y} ${belowBlock.location.z} air destroy`);
            } else {
                break;
            }
        }
    }
})


function findAirBlock(block) {
    for (const direction of directions) {
        const directedBlock = direction.block(block, 1);
        const belowDirectedBlock = directedBlock?.below();

        if (directedBlock?.isAir && (belowDirectedBlock?.typeId === "aria_ah:grass" || belowDirectedBlock?.typeId === "aria_ah:dirt" || belowDirectedBlock?.typeId === "aria_ah:farmland")) {
            return direction;
        }
    }

    return null;
}
