import { world, system, ItemStack, ItemDurabilityComponent, GameMode, ItemEnchantableComponent, } from "@minecraft/server";
import { randomNum } from "../math/randomNumbers";
import { BlockManager } from "../block/manager";
import { ItemManager } from "../item/manager";
export class shovelminerManager {
    static gravityBlockIDs = ["minecraft:gravel"];
    static gravelIDs = ["minecraft:gravel", "minecraft:clay"];
    static gravelData = [
        {
            id: "minecraft:gravel",
            chance: 0,
            itemPerLevel: 0,
            item: "minecraft:flint",
            level: 0,
        },
        {
            id: "minecraft:clay",
            chance: 0,
            itemPerLevel: 0,
            item: "minecraft:clay_ball",
            level: 0,
        },
    ];
    static start(player, brokenBlock, item, mainhand) {
        const durComp = item.getComponent(ItemDurabilityComponent.componentId);
        if (!durComp)
            return;
        const enchComp = item.getComponent(ItemEnchantableComponent.componentId);
        let fortuneLevel = undefined;
        let unbreakingLevel = undefined;
        let hasSilkTouch = false;
        if (enchComp) {
            if (enchComp.hasEnchantment("unbreaking")) {
                unbreakingLevel = enchComp.getEnchantment("unbreaking")
                    .level;
            }
            if (enchComp.hasEnchantment("silk_touch")) {
                hasSilkTouch = true;
            }
            else {
                if (enchComp.hasEnchantment("fortune")) {
                    fortuneLevel = enchComp.getEnchantment("fortune")
                        .level;
                }
                if (enchComp.hasEnchantment("unbreaking")) {
                    unbreakingLevel = enchComp.getEnchantment("unbreaking").level;
                }
            }
        }
        const blockData = this.gravelData.find((f) => f.id == brokenBlock.typeId);
        if (!blockData)
            return;
        this.getBlocks(brokenBlock, player, item, mainhand, durComp, blockData, fortuneLevel, unbreakingLevel, hasSilkTouch);
    }
    static limit = 64;
    static getBlocks(block, source, item, mainhand, durComp, gravelData, fortune, unbreakingLevel, hasSilkTouch) {
        const initialBlockLocation = block.location;
        let durability = durComp.damage;
        let blockNum = 0;
        let stop = false;
        const deniedLocs = [];
        function tick(block, takeDur, fortunable) {
            deniedLocs.push(block.location);
            if (blockNum >= shovelminerManager.limit)
                return;
            if (stop == true)
                return;
            const sameID = block.typeId;
            const blocks = BlockManager.getBlocksAround(block);
            if (fortunable) {
                if (!(shovelminerManager.gravityBlockIDs.includes(block.typeId) &&
                    block.location.x == initialBlockLocation.x &&
                    block.location.z == initialBlockLocation.z &&
                    block.location.y == initialBlockLocation.y + 1))
                    shovelminerManager.break(block, fortune, gravelData, fortunable, hasSilkTouch);
            }
            if (takeDur == true &&
                ItemManager.reduceDurability(unbreakingLevel) &&
                !(shovelminerManager.gravityBlockIDs.includes(block.typeId) &&
                    block.location.x == initialBlockLocation.x &&
                    block.location.z == initialBlockLocation.z &&
                    block.location.y == initialBlockLocation.y + 1)) {
                durability = durability + 1;
                if (durability >= durComp.maxDurability) {
                    stop = true;
                    return;
                }
            }
            for (const newblock of blocks) {
                if (newblock != undefined) {
                    const newloc = newblock.location;
                    if ((newblock.typeId == sameID) &&
                        !shovelminerManager.isDenied(newloc, deniedLocs)) {
                        blockNum = blockNum + 1;
                        if (source.getGameMode() != GameMode.creative) {
                            tick(newblock, true, true);
                        }
                        else {
                            tick(newblock, false, true);
                        }
                    }
                }
            }
        }
        tick(block, true, false);
        if (durability >= durComp.maxDurability) {
            stop = true;
            system.runTimeout(() => {
                source.dimension.playSound("random.break", source.location);
                mainhand.setItem(undefined);
            });
            return;
        }
        else {
            system.runTimeout(() => {
                durComp.damage = durability;
                mainhand.setItem(item);
            });
        }
    }
    static isDenied(blockLoc, deniedList) {
        let isDenied = false;
        for (const loc of deniedList) {
            if (blockLoc.x == loc.x && blockLoc.y == loc.y && blockLoc.z == loc.z)
                isDenied = true;
        }
        return isDenied;
    }
    static break(block, fortune, gravelData, fortunable, silkTouched) {
        const typeId = block.typeId;
        const { x, y, z } = block.location;
        const center = block.center();
        system.runTimeout(() => {
            if (silkTouched) {
                const lastRule = world.gameRules.doTileDrops;
                world.gameRules.doTileDrops = false;
                BlockManager.destroyBlock(block.dimension, block.location);
                world.gameRules.doTileDrops = lastRule;
                const item = new ItemStack(typeId, 1);
                const itemEntity = ItemManager.spawnItem(item, block.dimension, {
                    x: center.x,
                    y: center.y - 0.4,
                    z: center.z,
                });
                itemEntity?.applyImpulse({
                    x: randomNum(-0.1, 0.1),
                    y: randomNum(0.1, 0.25),
                    z: randomNum(-0.1, 0.1),
                });
            }
            else {
                if (typeId == "minecraft:gravel") {
                    if (fortune && fortunable) {
                        const lastRule = world.gameRules.doTileDrops;
                        world.gameRules.doTileDrops = false;
                        BlockManager.destroyBlock(block.dimension, block.location);
                        world.gameRules.doTileDrops = lastRule;
                        let itemID = "minecraft:gravel";
                        if (fortune != 3) {
                            const extra = this.calculateExtraItems(1, 0.33, fortune);
                            if (extra != 0) {
                                itemID = "minecraft:flint";
                            }
                        }
                        else
                            itemID = "minecraft:flint";
                        const item = new ItemStack(itemID, 1);
                        const itemEntity = ItemManager.spawnItem(item, block.dimension, {
                            x: center.x,
                            y: center.y - 0.4,
                            z: center.z,
                        });
                        itemEntity?.applyImpulse({
                            x: randomNum(-0.1, 0.1),
                            y: randomNum(0.1, 0.25),
                            z: randomNum(-0.1, 0.1),
                        });
                    }
                    else {
                        BlockManager.destroyBlock(block.dimension, block.location);
                    }
                }
                else {
                    BlockManager.destroyBlock(block.dimension, block.location);
                }
            }
        });
    }
    static calculateExtraItems(itemsPerLevel, chance, fortuneLevel) {
        let extra = 0;
        for (let i = 0; i < fortuneLevel; i++) {
            for (let i = 0; i < itemsPerLevel; i++) {
                const num = randomNum(0, 1);
                if (num <= chance) {
                    extra = extra + 1;
                }
            }
        }
        return extra;
    }
}
