import { BlockLocation, system, world } from "@minecraft/server"
import { ActionFormData } from "@minecraft/server-ui"
import "./worldTicksEvents"

system.events.beforeWatchdogTerminate.subscribe(sys => { sys.cancel = true })

const nonBreakableBlocks = [
    'minecraft:air',
    'minecraft:lava',
    'minecraft:water',
    'minecraft:bedrock',
    'minecraft:obsidian',
    'effect99:quarry_drill',
    'effect99:steam_engine',
    'minecraft:moving_block',
    'minecraft:flowing_lava',
    'minecraft:flowing_water',
    'effect99:chunks_viewer',
    'effect99:steam_generator',
    'minecraft:ancient_debris',
    'minecraft:crying_obsidian',
    'effect99:quarry_structure',
    'minecraft:end_portal_frame',
    'minecraft:reinforced_deepslate',
    'minecraft:piston_arm_collision',
    'effect99:medium_quarry_structure',
    'effect99:largue_quarry_structure',
    'minecraft:sticky_piston_arm_collision'
]

world.events.entityCreate.subscribe(e => {
    if (e.entity.typeId === 'entity:quarry_function') {
        if (e.entity.getComponent('minecraft:mark_variant').value === 0) {
            quarryFunctions(e.entity, 1)
        } else if (e.entity.getComponent('minecraft:mark_variant').value === 1) {
            quarryFunctions(e.entity, 2)
        } else if (e.entity.getComponent('minecraft:mark_variant').value === 2) {
            quarryFunctions(e.entity, 3)
        }
    }
    if (e.entity.typeId === 'entity:drill_function') {
        let { x, y, z } = e.entity.location
        x = Math.floor(x); y = Math.floor(y); z = Math.floor(z)
        switch (e.entity.getComponent('minecraft:mark_variant').value) {
            case 0: blockDestroy(x, y + 1, z, e.entity.dimension.id, x, y, z)
                break
            case 1: blockDestroy(x, y - 1, z, e.entity.dimension.id, x, y, z)
                break
            case 2: blockDestroy(x, y, z + 1, e.entity.dimension.id, x, y, z)
                break
            case 3: blockDestroy(x, y, z - 1, e.entity.dimension.id, x, y, z)
                break
            case 4: blockDestroy(x + 1, y, z, e.entity.dimension.id, x, y, z)
                break
            case 5: blockDestroy(x - 1, y, z, e.entity.dimension.id, x, y, z)
                break
        }
    }
})

const non_pushable_blocks = [
    'effect99:mechanical_arm',
    'effect99:fast_mechanical_arm',
    'effect99:regular_mechanical_arm',
    'effect99:antenna_base',
    'effect99:antenna',
    'effect99:antenna_signal',
    'effect99:steam_engine',
    'effect99:chunks_viewer',
    'effect99:steam_generator',
    'effect99:quarry_structure',
    'effect99:medium_quarry_structure',
    'effect99:largue_quarry_structure'
]

world.events.beforePistonActivate.subscribe(p => {
    for (const { x, y, z } of p.piston.attachedBlocks) {
        if (non_pushable_blocks.includes(world.getDimension(p.dimension.id).getBlock(new BlockLocation(x, y, z)).typeId)) {
            p.cancel = true
        }
        if (world.getDimension(p.dimension.id).getBlock(new BlockLocation(x, y, z)).typeId === 'effect99:quarry_drill') {
            const rotation = world.getDimension(p.dimension.id).getBlock(new BlockLocation(x, y, z)).permutation.getProperty('block:rotation').value
            switch (rotation) {
                case 0: blockDestroy(x, y + 2, z, p.dimension.id, x, y, z, true, x, y + 1, z, rotation)
                    break
                case 1: blockDestroy(x, y - 2, z, p.dimension.id, x, y, z, true, x, y - 1, z, rotation)
                    break
                case 2: blockDestroy(x, y, z + 2, p.dimension.id, x, y, z, true, x, y, z + 1, rotation)
                    break
                case 3: blockDestroy(x, y, z - 2, p.dimension.id, x, y, z, true, x, y, z - 1, rotation)
                    break
                case 4: blockDestroy(x + 2, y, z, p.dimension.id, x, y, z, true, x + 1, y, z, rotation)
                    break
                case 5: blockDestroy(x - 2, y, z, p.dimension.id, x, y, z, true, x - 1, y, z, rotation)
                    break
            }
        }
    }
})

function blockDestroy(rx, ry, rz, dimension, x, y, z, piston = false, dx = rx, dy = ry, dz = rz, r = 0) {
    const block = world.getDimension(dimension).getBlock(new BlockLocation(x, y, z)).permutation
    const typeId = world.getDimension(dimension).getBlock(new BlockLocation(rx, ry, rz)).typeId
    if (!piston) {
        if (block.getProperty('block:energy').value) {
            if (!nonBreakableBlocks.includes(typeId)) {
                block.getProperty('block:energy').value -= 1
                world.getDimension(dimension).getBlock(new BlockLocation(x, y, z)).setPermutation(block)
                world.getDimension(dimension).runCommandAsync(`setblock ${rx} ${ry} ${rz} air 0 destroy`)
            }
        }
    } else {
        const ticks = (t = 2) => system.run(() => {
            try {
                const block = world.getDimension(dimension).getBlock(new BlockLocation(dx, dy, dz)).permutation
                if (!t && r === world.getDimension(dimension).getBlock(new BlockLocation(dx, dy, dz)).permutation.getProperty('block:rotation').value) {
                    block.getProperty('block:cooldown').value = 2
                    if (block.getProperty('block:energy').value) {
                        if (!nonBreakableBlocks.includes(typeId) && !typeId.includes('deepslate')) {
                            block.getProperty('block:energy').value -= 1
                            world.getDimension(dimension).runCommandAsync(`setblock ${rx} ${ry} ${rz} air 0 destroy`)
                        }
                    } else if (piston) {
                        if (!nonBreakableBlocks.includes(typeId) && !typeId.includes('deepslate')) {
                            world.getDimension(dimension).runCommandAsync(`setblock ${rx} ${ry} ${rz} air 0 destroy`)
                        }
                    }
                    world.getDimension(dimension).getBlock(new BlockLocation(dx, dy, dz)).setPermutation(block)
                }
            } catch (e) { }
            if (t) ticks(t - 1)
        })
        ticks()
    }
}

const panelMenus = [
    'effect99:steam_generator',
    'effect99:steam_engine',
    'effect99:inefficient_steam_generator',
    'effect99:inefficient_steam_engine'
]

world.events.beforeItemUseOn.subscribe(i => {
    const { x, y, z } = i.blockLocation
    const block = world.getDimension(i.source.dimension.id).getBlock(new BlockLocation(x, y, z))
    const player = i.source

    if (!player.hasTag("Form") && block.hasTag('machine_panel') && panelMenus.includes(block.typeId)) {
        player.addTag("Form")
        const panel = new ActionFormData()
            .title(`${block.typeId.includes('engine') ? 'Steam Engine' : 'Steam Generator'}`)
            .body('Dismantle Machine?').button('Yes').button('No')

        panel.show(player).then(r => {
            if (r.selection === 0) {
                if (block.hasTag('north_block')) {
                    !block.typeId.includes('inefficient') ?
                        player.runCommandAsync(`fill ${x - 1} ${y - 1} ${z - 2} ${x + 1} ${y + 1} ${z} air 0`) :
                        player.runCommandAsync(`fill ${x - 1} ${y - 1} ${z - 2} ${x + 1} ${y} ${z} air 0`)
                }
                else if (block.hasTag('south_block')) {
                    !block.typeId.includes('inefficient') ?
                        player.runCommandAsync(`fill ${x + 1} ${y + 1} ${z + 2} ${x - 1} ${y - 1} ${z} air 0`) :
                        player.runCommandAsync(`fill ${x + 1} ${y} ${z + 2} ${x - 1} ${y - 1} ${z} air 0`)
                }
                else if (block.hasTag('west_block')) {
                    !block.typeId.includes('inefficient') ?
                        player.runCommandAsync(`fill ${x - 2} ${y - 1} ${z - 1} ${x} ${y + 1} ${z + 1} air 0`) :
                        player.runCommandAsync(`fill ${x - 2} ${y - 1} ${z - 1} ${x} ${y} ${z + 1} air 0`)
                }
                else if (block.hasTag('east_block')) {
                    !block.typeId.includes('inefficient') ?
                        player.runCommandAsync(`fill ${x + 2} ${y + 1} ${z + 1} ${x} ${y - 1} ${z - 1} air 0`) :
                        player.runCommandAsync(`fill ${x + 2} ${y} ${z + 1} ${x} ${y - 1} ${z - 1} air 0`)
                }
                if (block.typeId.includes('steam_engine') && !block.typeId.includes('inefficient')) {
                    player.runCommandAsync(`execute @s ~~~ loot spawn ${x} ${y} ${z} loot "blocks/steam_engine"`)
                }
                else if (block.typeId.includes('steam_generator') && !block.typeId.includes('inefficient')) {
                    player.runCommandAsync(`execute @s ~~~ loot spawn ${x} ${y} ${z} loot "blocks/steam_generator"`)
                }
                else if (block.typeId.includes('steam_engine') && block.typeId.includes('inefficient')) {
                    player.runCommandAsync(`execute @s ~~~ loot spawn ${x} ${y} ${z} loot "blocks/experimental_steam_engine"`)
                }
                else if (block.typeId.includes('steam_generator') && block.typeId.includes('inefficient')) {
                    player.runCommandAsync(`execute @s ~~~ loot spawn ${x} ${y} ${z} loot "blocks/experimental_steam_generator"`)
                }
            }
            player.removeTag("Form")
        })
    }
})

const qNonBreakableBlocks = [
    'minecraft:bedrock',
    'minecraft:end_portal_frame',
    'minecraft:lava',
    'minecraft:water',
    'minecraft:flowing_lava',
    'minecraft:flowing_water',
    'effect99:steam_engine',
    'effect99:steam_generator',
    'effect99:quarry_structure',
    'effect99:medium_quarry_structure',
    'effect99:largue_quarry_structure',
    'minecraft:mob_spawner'
]

function quarryFunctions(e, r) {
    let warning = false
    let { x, y, z } = e.location
    x = Math.floor(x); y = Math.floor(y); z = Math.floor(z)
    for (let i = -r; i <= r; i++) {
        for (let k = -r; k <= r; k++) {
            const block = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x + i, y, z + k))
            if (qNonBreakableBlocks.includes(block.typeId)) { // warning
                for (let l = 0; l < 320; l++) {
                    const b = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z))
                    if (b.hasTag('quarry_center') && !b.hasTag('power_on_0')) {
                        warning = true
                        const permutation = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).permutation
                        permutation.getProperty('cooldown:time').value = 6
                        world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).setPermutation(permutation)
                        e.triggerEvent('despawn')
                        break
                    }
                    else if (b.hasTag('warning')) {
                        warning = true
                        break
                    }
                }
                break
            }
        }
    }
    const block = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + 1, z))
    if (!block.hasTag('warning') && block.hasTag('quarry_structure_drill')) { //fill
        for (let l = 0; l < 320; l++) {
            const b = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z))
            if (y + l === 319) break
            else if (b.hasTag('quarry_center') && !block.hasTag('warning') && !b.hasTag('power_on_0') && !b.hasTag('power_on_1') && !b.hasTag('quarry_center_off') && !warning) {
                e.triggerEvent('fill_cooldown')
                const permutation = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).permutation
                permutation.getProperty('power:on').value -= 1
                world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).setPermutation(permutation)
                break
            } else if (b.hasTag('quarry_center')) {
                e.triggerEvent('despawn')
                break
            }
        }
    } else if (block.hasTag('warning')) { //valid
        for (let i = -r; i <= r; i++) {
            for (let k = -r; k <= r; k++) {
                const block = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x + i, y, z + k))
                if (qNonBreakableBlocks.includes(block.typeId)) warning = true
            }
        }
        if (!warning) {
            for (let l = 0; l < 320; l++) {
                const b = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z))
                if (y + l === 319) break
                else if (b.hasTag('quarry_center') && block.hasTag('warning') && !b.hasTag('power_on_0')) {
                    e.triggerEvent('fill_cooldown')
                    const permutation = world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).permutation
                    permutation.getProperty('cooldown:time').value = 4
                    world.getDimension(e.dimension.id).getBlock(new BlockLocation(x, y + l, z)).setPermutation(permutation)
                    e.triggerEvent('despawn')
                    break
                }
            }
        }
    }
}

world.events.beforeChat.subscribe(chat => {
    if (chat.message === '!rTags') {
        chat.cancel = true
        for (const player of world.getPlayers()) {
            for (let i = 0; player.getTags()[0]; i++) {
                player.removeTag(`${player.getTags()[0]}`)
            }
        }
    }
})