import { system, ItemStack, EnchantmentType } from "@minecraft/server"


export class DrillComponent {
    constructor() {
        this.onTick = this.onTick.bind(this);
        this.onPlayerInteract = this.onPlayerInteract.bind(this);
        this.onPlace = this.onPlace.bind(this);

        this.inMining = {}
        this.tickCpt = 0
        this.REDSTONE_POWER_BLOCKS = [
            { id: "minecraft:redstone_wire", state: "redstone_signal" },
            { id: "minecraft:powered_comparator", state: "minecraft:cardinal_direction" },
            { id: "minecraft:powered_repeater", state: "minecraft:cardinal_direction" },
            { id: "minecraft:redstone_torch", state: "torch_facing_direction" },
            { id: "minecraft:observer", state: "minecraft:facing_direction" },
            { id: "minecraft:lever", state: "open_bit" },
            { id: "minecraft:lever", state: "open_bit" },
            { id: "_button", state: "button_pressed_bit" },
            { id: "_pressure_plate", state: "redstone_signal" },
            { id: "minecraft:redstone_block", state: null },
        ];
        this.ENCHANTMENT_TYPES = [
            { type: "efficiency", level: 1 },
            { type: "efficiency", level: 2 },
            { type: "efficiency", level: 3 },
            { type: "efficiency", level: 4 },
            { type: "efficiency", level: 5 },
            { type: "fortune", level: 1 },
            { type: "fortune", level: 2 },
            { type: "fortune", level: 3 },
            { type: "silk_touch", level: 1 }
        ];
        this.BANNED_BLOCK = [
            "minecraft:bedrock",
            "minecraft:light_block",
            "minecraft:reinforced_deepslate",
            "minecraft:barrier",
            "minecraft:end_portal_frame",
            "minecraft:structure_block",
            "minecraft:structure_void",
            "minecraft:command_block",
            "minecraft:chain_command_block",
            "minecraft:repeating_command_block",
            "minecraft:water",
            "minecraft:flowing_water",
            "minecraft:lava",
            "minecraft:flowing_lava",
        ]

        this.MINECRAFT_ORES = [
            "minecraft:coal_ore",
            "minecraft:deepslate_coal_ore",
            "minecraft:iron_ore",
            "minecraft:deepslate_iron_ore",
            "minecraft:copper_ore",
            "minecraft:deepslate_copper_ore",
            "minecraft:gold_ore",
            "minecraft:deepslate_gold_ore",
            "minecraft:redstone_ore",
            "minecraft:lit_redstone_ore",
            "minecraft:deepslate_redstone_ore",
            "minecraft:lit_deepslate_redstone_ore",
            "minecraft:emerald_ore",
            "minecraft:deepslate_emerald_ore",
            "minecraft:lapis_ore",
            "minecraft:deepslate_lapis_ore",
            "minecraft:diamond_ore",
            "minecraft:deepslate_diamond_ore",
            "minecraft:nether_gold_ore",
            "minecraft:quartz_ore",
            "minecraft:ancient_debris"
        ];

        this.MINECRAFT_ORES_LOOT = [
            "minecraft:coal",
            "minecraft:coal",
            "minecraft:raw_iron",
            "minecraft:raw_iron",
            "minecraft:raw_copper",
            "minecraft:raw_copper",
            "minecraft:raw_gold",
            "minecraft:raw_gold",
            "minecraft:redstone",
            "minecraft:redstone",
            "minecraft:redstone",
            "minecraft:redstone",
            "minecraft:emerald",
            "minecraft:emerald",
            "minecraft:lapis_lazuli",
            "minecraft:lapis_lazuli",
            "minecraft:diamond",
            "minecraft:diamond",
            "minecraft:gold_nugget",
            "minecraft:quartz",
            "minecraft:ancient_debris"
        ];

        this.MINECRAFT_STONE_TYPES = [
            "minecraft:cobblestone",
            "minecraft:stone",
            "minecraft:granite",
            "minecraft:diorite",
            "minecraft:andesite",
            "minecraft:tuff",
            "minecraft:deepslate",
            "minecraft:cobbled_deepslate",
            "minecraft:dripstone_block",
            "minecraft:calcite",
            "minecraft:basalt",
            "minecraft:smooth_basalt",
            "minecraft:blackstone",
            "minecraft:gilded_blackstone"
        ];

        this.MAX_ORES_BREAK = 30

    }

    onPlace(e) {
        const block = e.block;
        const entity = block.dimension.spawnEntity("pb_red:drill_entity", { x: block.location.x + 0.5, y: block.location.y, z: block.location.z + 0.5 })
        let direction = (block.permutation.getState('minecraft:facing_direction'));
        block.setPermutation(block.permutation.withState("pb_red:is_placed", true))
        if (direction == "up" || direction == "down") {
            if (direction == "up")
                entity.setProperty("pb_red:pitch_rot", 90)
            if (direction == "down")
                entity.setProperty("pb_red:pitch_rot", -90)
            entity.setProperty("pb_red:yaw_rot", 0)
        } else {
            const rotation = this.getRoationFromDirection(direction)
            entity.setProperty("pb_red:yaw_rot", rotation)
            entity.setProperty("pb_red:pitch_rot", 0)
        }
    }

    getRoationFromDirection(direction) {
        switch (direction) {
            case 'north':
                return 0;
            case 'south':
                return 180;
            case 'east':
                return 90;
            case 'west':
                return -90;
            default:
                return 0;
        }
    }

    onPlayerInteract(e) {
        // console.warn("interact");
        const block = e.block;
        const player = e.player;
        let selectedSlot = player.selectedSlotIndex;
        let handItem = player.getComponent("inventory").container.getItem(selectedSlot);

        if (handItem?.typeId == "pb_red:redstone_wrench") {
            const efficiency = block.permutation.getState('pb_red:efficiency')
            const fortune = block.permutation.getState('pb_red:fortune')
            const silkTouch = block.permutation.getState('pb_red:silk_touch')

            block.dimension.runCommand(`playsound random.click @a ${block.location.x} ${block.location.y} ${block.location.z}`)
            player.sendMessage(`Drill upgrades:${(efficiency == 0 && fortune == 0 && silkTouch == 0) ? "\n- §cNone§r" : ""}${(efficiency > 0) ? ("\n- §dEfficiency§5 " + efficiency + "§r") : ""}${(fortune > 0) ? ("\n- §dFortune§5 " + fortune + "§r") : ""}${(silkTouch > 0) ? ("\n- §dSilk Touch§r") : ""}`)
            return;
        }

        if (handItem?.typeId.includes('enchanted_book')) {
            const enchantment = handItem.getComponent("enchantable");

            for (let i = 0; i < this.ENCHANTMENT_TYPES.length; i++) {
                let enchantmentType = this.ENCHANTMENT_TYPES[i];
                if (enchantment.hasEnchantment(new EnchantmentType(enchantmentType.type))) {
                    const hasFortune = block.permutation.getState('pb_red:fortune') !== 0
                    const hasSilkTouch = block.permutation.getState('pb_red:silk_touch') !== 0
                    if (enchantmentType.type == "silk_touch" && hasFortune) {
                        player.runCommand(`tellraw @s {"rawtext":[{"text":"§cCan't upgrade Drill with §4Silk Touch§c because it already have §4Fortune§c upgrade."}]}`)
                        return;
                    }
                    if (enchantmentType.type == "fortune" && hasSilkTouch) {
                        player.runCommand(`tellraw @s {"rawtext":[{"text":"§cCan't upgrade Drill with §4Fortune§c because it already have §4Silk Touch§c upgrade."}]}`)
                        return;
                    }
                    let enchantLevel = enchantment.getEnchantment(new EnchantmentType(enchantmentType.type)).level;
                    block.setPermutation(block.permutation.withState(`pb_red:${enchantmentType.type}`, enchantLevel));
                    player.getComponent("inventory").container.setItem(selectedSlot, null);
                    player.runCommand(`tellraw @s {"rawtext":[{"text":"Upgraded Drill with §d${enchantmentType.type == "silk_touch" ? "silk touch" : enchantmentType.type} ${enchantmentType.type == "silk_touch" ? "" : enchantLevel}."}]}`)
                    block.dimension.runCommand(`playsound random.orb @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                    this.tickCpt = 1
                    return;
                }
            }
        }
    }
    getOppositeDirection(direction) {
        switch (direction) {
            case 'north':
                return 'south';
            case 'south':
                return 'north';
            case 'east':
                return 'west';
            case 'west':
                return 'east';
            case 'up':
                return 'down';
            case 'down':
                return 'up';
        }
    }

    getFrontBlock(direction, block) {
        switch (direction) {
            case 'north':
                return block.north();
            case 'south':
                return block.south();
            case 'east':
                return block.east();
            case 'west':
                return block.west();
            case 'up':
                return block.above();
            case 'down':
                return block.below();
        }
    }

    breakOresAndAdjacent(block, drill) {
        const silkTouchActive = drill.permutation.getState('pb_red:silk_touch')
        //  console.warn(silkTouchActive)
        const oresToCheck = [block];
        let oresToBreakCount = 0

        let blockCount = [
            {
                id: silkTouchActive == 1 ? block.typeId : this.MINECRAFT_ORES_LOOT[this.MINECRAFT_ORES.indexOf(block.typeId)],
                location: { x: block.location.x, y: block.location.y, z: block.location.z }
            }
        ]
        while (oresToCheck.length > 0) {
            const currentBlock = oresToCheck.pop();
            if (this.MINECRAFT_ORES.includes(currentBlock.typeId)) {
                currentBlock.dimension.runCommand(`setblock ${currentBlock.location.x} ${currentBlock.location.y} ${currentBlock.location.z} air replace`)
                currentBlock.dimension.runCommand(`summon xp_orb ${currentBlock.location.x} ${currentBlock.location.y} ${currentBlock.location.z}`)
                currentBlock.dimension.runCommand(`playsound dig.stone @p ${currentBlock.location.x} ${currentBlock.location.y} ${currentBlock.location.z}`)

                oresToBreakCount++
                if (oresToBreakCount > this.MAX_ORES_BREAK) return blockCount

                const north = currentBlock.north();
                const east = currentBlock.east();
                const south = currentBlock.south();
                const west = currentBlock.west();
                const above = currentBlock.above();
                const below = currentBlock.below();

                const adjacentBlocks = [north, east, south, west, above, below];
                for (const adjacentBlock of adjacentBlocks) {
                    if (this.MINECRAFT_ORES.includes(adjacentBlock.typeId)) {
                        oresToCheck.push(adjacentBlock);
                        blockCount.push(
                            {
                                id: silkTouchActive == 1 ? adjacentBlock.typeId : this.MINECRAFT_ORES_LOOT[this.MINECRAFT_ORES.indexOf(adjacentBlock.typeId)],
                                location: { x: adjacentBlock.location.x, y: adjacentBlock.location.y, z: adjacentBlock.location.z }
                            }
                        )
                    }
                }
            }
        }
        return blockCount
    }

    onTick(e) {
        const block = e.block;
        let direction = this.getOppositeDirection(block.permutation.getState('minecraft:facing_direction'));
        const north = block.north();
        const east = block.east();
        const south = block.south();
        const west = block.west();
        const above = block.above();
        const below = block.below();

        const adjacentBlocks = [north, east, south, west, above, below];
        const directionList = ["north", "east", "south", "west", "up", "down"];
        let hasRedstonePower = this.hasRedstonePower(adjacentBlocks, directionList);

        if (!block.permutation.matches("pb_red:drill")) return

        let efficiencyLvl = block.permutation.getState('pb_red:efficiency')

        const drillEntity = block.dimension.getEntities({ location: { x: block.location.x + 0.5, y: block.location.y, z: block.location.z + 0.5 }, maxDistance: 1, type: "pb_red:drill_entity" })[0]
        if (!drillEntity) return
        drillEntity.setProperty("pb_red:drill_efficiency", efficiencyLvl)
        drillEntity.setProperty("pb_red:powered", hasRedstonePower)

        if (!hasRedstonePower) {
            try {
                block.setPermutation(block.permutation.withState('pb_red:powered', false));
            } catch { }
            return;
        }
        try {
            block.setPermutation(block.permutation.withState('pb_red:powered', true));
        } catch { }
        let miningDuration = Math.abs(block.permutation.getState('pb_red:efficiency') - 5)
        this.tickCpt++

        if (this.tickCpt % 22 == 0 || this.tickCpt == 1) {
            block.dimension.runCommand(`playsound pb_red.drill_${efficiencyLvl} @a ${block.location.x} ${block.location.y} ${block.location.z} 0.2`)
        }

        let frontBlock = this.getFrontBlock(direction, block);
        if (!frontBlock) return
        if (frontBlock.typeId == "minecraft:air") return
        if (this.inMining[drillEntity.id] == true) return
        if (this.MINECRAFT_ORES.includes(frontBlock.typeId)) {
            this.inMining[drillEntity.id] = true
            system.runTimeout(() => {
                if (this.hasRedstonePower(adjacentBlocks, directionList)) {
                    let count = this.breakOresAndAdjacent(frontBlock, block);
                    const fortuneMultiplier = block.permutation.getState('pb_red:fortune')
                    count.forEach((spawnBlock) => {
                        try {
                            block.dimension.spawnItem(new ItemStack(spawnBlock.id, spawnBlock.id == "minecraft:ancient_debris" ? 1 : fortuneMultiplier + 1), { x: spawnBlock.location.x, y: spawnBlock.location.y, z: spawnBlock.location.z })
                        } catch {
                            //console.warn("error Drill Loot")
                        }
                    })
                }
                this.inMining[drillEntity.id] = false
            }, 5 + (miningDuration * 20))
        } else {
            //console.warn(frontBlock.typeId)
            if (this.BANNED_BLOCK.includes(frontBlock.typeId)) return
            this.inMining[drillEntity.id] = true
            system.runTimeout(() => {
                try {
                    if (this.hasRedstonePower(adjacentBlocks, directionList)) {
                        frontBlock.dimension.runCommand(`setblock ${frontBlock.location.x} ${frontBlock.location.y} ${frontBlock.location.z} air destroy`)
                    }
                } catch { }

                this.inMining[drillEntity.id] = false
            }, 5 + (miningDuration * 20) + (this.MINECRAFT_STONE_TYPES.includes(frontBlock.typeId) ? 0 : 25))
        }
    }

    hasRedstonePower(adjacentBlocks, directionList) {

        return adjacentBlocks.some((adjacentBlock, index) => {
            if (!adjacentBlock) return false;

            const redstoneBlock = this.REDSTONE_POWER_BLOCKS.find(({ id }) => adjacentBlock.typeId.includes(id));
            if (!redstoneBlock) return false;

            const { id, state } = redstoneBlock;
            if (id === "minecraft:redstone_block") return true;

            if (id === "minecraft:redstone_wire") {
                let redstonePowerState = adjacentBlock.permutation.getState(state);
                return redstonePowerState > 0;
            }

            if (id === "minecraft:powered_comparator" || id === "minecraft:powered_repeater") {
                return adjacentBlock.permutation.getState(state) === directionList[index];
            }

            if (id === "minecraft:redstone_torch") {
                return adjacentBlock.permutation.getState(state) !== this.getOppositeDirection(directionList[index]) && index !== 4;
            }

            if (id === "minecraft:observer") {
                return adjacentBlock.permutation.getState(state) == directionList[index] && adjacentBlock.permutation.getState("powered_bit") == true;
            }

            if (id === "minecraft:lever") {
                return adjacentBlock.permutation.getState(state) == true;
            }

            if (id === "_button") {
                return adjacentBlock.permutation.getState(state) == true;
            }

            if (id === "_pressure_plate") {
                return adjacentBlock.permutation.getState(state) > 0;
            }

            return false;
        });
    }
}
