import { world, system, BlockVolume, ScriptEventCommandMessageAfterEvent, EntityComponentTypes, ItemStack } from "@minecraft/server"
import { ActionFormData } from '@minecraft/server-ui'
import { VectorUtilities } from "./libs/vectorUtilities"

class scriptEventTriggers {
    /** @param {ScriptEventCommandMessageAfterEvent} evt */
    "lb_ga:melon_golem"(evt) {
        const golem = evt.sourceEntity

        const playersArround = golem.dimension.getPlayers({ location: golem.location, maxDistance: 15 }).filter(element => element.getComponent('minecraft:health').currentValue < element.getComponent('minecraft:health').effectiveMax / 2)
        playersArround.forEach(player => player.addEffect('regeneration', 50, { amplifier: 2 }))
    }
    /** @param {ScriptEventCommandMessageAfterEvent} evt */
    "lb_ga:hopper"(evt) {
        const golem = evt.sourceEntity

        const itemsArround = golem.dimension.getEntities({ location: golem.location, maxDistance: 10, minDistance: 2, families: ['monster'] })

        itemsArround.forEach(item => {
            const direction = VectorUtilities.div(VectorUtilities.directionTo(item.location, golem.location), { x: 4, y: 4, z: 4 })
            item.applyImpulse(direction)
        })
    }
    /** @param {ScriptEventCommandMessageAfterEvent} evt */
    "lb_ga:amethyst"(evt) {
        const golem = evt.sourceEntity

        const lifeComponent = golem.getComponent("minecraft:health")
        const maxHealth = lifeComponent.effectiveMax
        const currentHealth = lifeComponent.currentValue

        if (maxHealth == currentHealth) return

        const amethystLevels = [
            {
                level: "minecraft:amethyst_cluster",
                healthRegen: 20
            },
            {
                level: "minecraft:large_amethyst_bud",
                healthRegen: 15
            },
            {
                level: "minecraft:medium_amethyst_bud",
                healthRegen: 10
            },
            {
                level: "minecraft:small_amethyst_bud",
                healthRegen: 5
            }
        ]

        const golemLocation = golem.location

        try {
            const volume = new BlockVolume(
                { x: golemLocation.x + 10, y: golemLocation.y + 10, z: golemLocation.z + 10 },
                { x: golemLocation.x - 10, y: golemLocation.y - 10, z: golemLocation.z - 10 }
            )

            const amethystsArround = golem.dimension.getBlocks(volume, { includeTypes: amethystLevels.map(element => element.level) })

            if (amethystsArround.getCapacity() == 0) return

            const array = Array.from(amethystsArround.getBlockLocationIterator())

            const amethystLocation = {
                x: array[0].x,
                y: array[0].y,
                z: array[0].z
            }

            const block = golem.dimension.getBlock(amethystLocation)
            const blockName = block.typeId
            const blockFace = block.permutation.getState("minecraft:block_face")
            const amethystEffectIndex = amethystLevels.findIndex(element => element.level == blockName)
            const amethystHealthEffect = amethystLevels[amethystEffectIndex]
            const newAmethystName = amethystLevels[amethystEffectIndex + 1]?.level.split(":")[1] ?? "air"
            const components = newAmethystName == "air" ? "" : `["minecraft:block_face"="${blockFace}"]`

            lifeComponent.setCurrentValue(currentHealth + amethystHealthEffect.healthRegen)

            golem.dimension.runCommand(`setblock ${amethystLocation.x} ${amethystLocation.y} ${amethystLocation.z} ${newAmethystName} ${components}`)
        } catch (error) {

        }
    }
    /** @param {ScriptEventCommandMessageAfterEvent} evt */
    "lb_ga:redstone_golem"(evt) {
        const golem = evt.sourceEntity

        const redstone_dust = golem.getProperty("lb_ga:redstone_dust")

        if (redstone_dust >= 8) {
            golem.setProperty("lb_ga:redstone_dust", redstone_dust - 8)
        }
    }
    /** @param {ScriptEventCommandMessageAfterEvent} evt */
    "lb_ga:remove_cobweb"(evt) {
        const entity = evt.sourceEntity
        const blockCoordinates = entity.location

        world.getPlayers().forEach((player) => {
            const block = player.dimension.getBlock(blockCoordinates)

            if (!block || block.isAir) return;

            system.runTimeout(() => {
                try {
                    block.setType('minecraft:air')
                } catch (e) {

                }
            }, 10 * 20)
        })
    }
}

const SET = new scriptEventTriggers()

system.afterEvents.scriptEventReceive.subscribe(evt => {
    if (typeof SET[evt.id] == "function") {
        SET[evt.id](evt)
    }
})

//*REDSTONE GOLEM
const MAX_REDSTONE_CAPACITY = 128

function redstoneForm(golem, player) {
    const form = new ActionFormData()


    const redstone_dust = golem.getProperty("lb_ga:redstone_dust")
    form.title({ translate: "form.redstone.title" })

    const bodyText = {
        rawtext: [
            { text: "\n" },
            {
                translate: "form.redstone.body.redstone_remain",
                with: [`${redstone_dust}`, `${MAX_REDSTONE_CAPACITY}`]
            },
            { text: "\n\n" }
        ]
    }
    form.body(bodyText)
    form.button({ translate: "text.button.ok" })

    form.show(player)
}

world.beforeEvents.playerInteractWithEntity.subscribe(event => {
    if (event.target.typeId !== "lb_ga:redstone_golem") return;
    if (event.player.getComponent("equippable")?.getEquipment("Mainhand")?.typeId === "minecraft:lead") return

    const item = event.player.getComponent("inventory").container.getItem(event.player.selectedSlotIndex);
    if (!item || item.typeId != "minecraft:redstone") {
        system.run(() => {
            redstoneForm(event.target, event.player);
        });
        return;
    }

    if (item.typeId === "minecraft:redstone") {
        const current_redstone_dust = event.target.getProperty("lb_ga:redstone_dust")

        if (current_redstone_dust < MAX_REDSTONE_CAPACITY) {

            system.run(() => {
                event.target.setProperty("lb_ga:redstone_dust", current_redstone_dust + 1)
                const pos = event.target.location;
                event.target.dimension.spawnParticle("lb_ga:redstone_dust", {
                    x: pos.x,
                    y: pos.y + 0.2,
                    z: pos.z
                });

                event.player.runCommand('/clear @s redstone 0 1')
            })
            return;
        }
    }
});

world.afterEvents.entityDie.subscribe(deathEvent => {
    const entity = deathEvent.deadEntity
    if (entity.typeId !== "lb_ga:redstone_golem") return
    let remainingRedstone = entity.getProperty('lb_ga:redstone_dust')
    while (remainingRedstone > 0) {
        let thisStack = 64
        if (remainingRedstone < 64) {
            thisStack = remainingRedstone
        }
        entity.dimension.spawnItem(new ItemStack("minecraft:redstone", thisStack), entity.location)
        remainingRedstone -= thisStack
    }
})

//*LAPIS GOLEM
world.afterEvents.entityDie.subscribe(deathEvent => {
    const source = deathEvent.damageSource.damagingEntity
    if (source && source.typeId === "lb_ga:lapis_golem") dropEntityXp(deathEvent.deadEntity)
})

function dropEntityXp(entity) {
    let xpAmount = getEntityExpDrop(entity)
    while (xpAmount > 0) {
        entity.dimension.spawnEntity("xp_orb", entity.location)
        xpAmount--
    }
}

const XPs = {
    animals: ["armadillo", "axolotl", "bee", "camel", "cat", "chicken", "cod", "cow", "dolphin", "donkey", "fox", "frog", "glow_squid", "goat", "happy_ghast", "hoglin", "horse", "llama", "mooshroom", "ocelot", "panda", "parrot", "pig ", "polar_bear", "pufferfish", "rabbit", "salmon", "sheep", "skeleton_horse", "sniffer", "squid", "strider", "trader_llama", "tropical_fish", "turtle", "wolf", "zombie_horse"],
    monsters: {
        three: ["endermite"],
        slime: ["magma_cube", "slime"],
        five: ["bogged", "cave_spider", "creeper", "drowned", "enderman", "ghast", "husk", "phantom", "piglin", "pillager", "shulker", "silverfish", "skeleton", "spider", "stray", "vex", "vindicator", "warden", "witch", "wither_skeleton", "zombie", "zombie_villager", "zoglin", "zombie_pigman"],
        ten: ["blaze", "breeze", "elder_guardian", "guardian"],
        baby: ["piglin", "drowned", "husk", "zombie", "zombie_villager", "zombie_pigman"], //piglin is 1, rest are 12!?!!!
        twenty: ["ravager", "piglin_brute"]
    },
    zero: ["evocation_illager", "ender_dragon"]
}

function getEntityExpDrop(entity) {
    const shortName = entity.typeId.split(":")[1]
    if (XPs.zero.includes(shortName)) return 0
    const isBaby = entity.hasComponent(EntityComponentTypes.IsBaby)
    if (XPs.monsters.baby.includes(shortName) && isBaby) {
        if (shortName === "piglin") return 1
        else return 12
    } else {
        if (XPs.animals.includes(shortName)) return (Math.floor(Math.random() * 3) + 1)
        if (XPs.monsters.three.includes(shortName)) return 3
        if (XPs.monsters.five.includes(shortName)) return 5
        if (XPs.monsters.ten.includes(shortName)) return 10
        if (XPs.monsters.twenty.includes(shortName)) return 20
        if (XPs.monsters.slime.includes(shortName)) return entity.getComponent(EntityComponentTypes.Variant).value
        if (shortName === "wither") return 50
        return 2
    }
}

//Quick solution to make the amethyst golems heal on their own.
world.afterEvents.entitySpawn.subscribe(event => {
    if (event.entity.typeId !== "lb_ga:amethyst_golem") return
    event.entity.addEffect("regeneration", 9999999, { amplifier: 1, showParticles: false })
})