import { system, world, ItemStack } from "@minecraft/server"
import { ActionFormData } from "@minecraft/server-ui"
import { compostItems } from "./main"
import { sendDebugMessage } from "./JMmcUtils"

export function boneData(entity) {
    function compostData() {
        const compostProperty = "lb_ga:compost_fill_level"

        function getCompostLevel() {
            return entity.getProperty(compostProperty)
        }

        return {
            get: getCompostLevel()
        }
    }

    function boneMealData() {
        if (entity.typeId !== "lb_ga:bone_golem") return undefined
        const inventory = entity.getComponent("inventory")?.container

        function getInventory() {
            let boneMealCount = 0
            for (let slot = 0; slot < inventory.size; slot++) {
                const item = inventory.getItem(slot)
                if (item && item.typeId === "minecraft:bone_meal" && item.amount) boneMealCount += item?.amount
            }
            return boneMealCount
        }

        function decrement() {
            for (let slot = inventory.size - 1; slot >= 0; slot--) {
                const item = inventory.getItem(slot)
                if (item && item.typeId === "minecraft:bone_meal") {
                    if (item.amount > 1) {
                        item.amount--
                        inventory.setItem(slot,item)
                        break
                    } else if (item.amount === 1) {
                        // clear slot
                        inventory.setItem(slot)
                        break
                    } else sendDebugMessage(`slot ${slot} did not have any bone meal: ${JSON.stringify(item)}`)
                }
            }
        }

        return {
            get: getInventory(),
            decrement: function() {
                return decrement()
            },
            capacity: inventory.size * 64
        }
    }

    function timesUsed() {
        const property = "lb_ga:bonemeal_successCount"
        if (!entity.getDynamicPropertyIds().includes(property)) set(0)

        function get() {
            return JSON.parse(entity.getDynamicProperty(property))
        }

        function set(value) {
            return entity.setDynamicProperty(property,JSON.stringify(value))
        }

        return {
            get: get(),
            increment: function(value = 1) {
                return set(get() + value)
            }
        }
    }

    function interval() {
        const property = "lb_ga:fertilize_interval"
        // initialize a 40 - 100 tick interval per golem
        if (!entity.getDynamicPropertyIds().includes(property)) entity.setDynamicProperty(property,JSON.stringify(Math.floor(Math.random() * 60) + 40))

        function get() {
            return JSON.parse(entity.getDynamicProperty(property))
        }

        return {
            get: get()
        }
    }

    return {
        interval:interval().get,
        compost:compostData(),
        boneMeal:boneMealData(),
        plants:timesUsed()
    }
}
 
function boneForm(golem) {
    const form = new ActionFormData()
    const data = boneData(golem)
    form.title({translate:"form.bone.title"})
    const bodyText = {
        rawtext: [
            {text:"\n"},
            {
                translate: "form.bone.body.boneMeal",
                with:[`${data.boneMeal.get}`,`${data.boneMeal.capacity}`]
            },
            {text:"\n\n"},
            {
                translate: "form.bone.body.fillPercent",
                with:[`${data.compost.get}`]
            },
            {text:"\n\n"},
            {
                translate: "form.bone.body.history",
                with:[`${data.plants.get}`]
            },
            {text:"\n\n"}
        ]
    }
    form.body(bodyText)
    form.button({translate:"text.button.ok"})
    return form
}

world.afterEvents.entitySpawn.subscribe(event => {
    if (event.entity.typeId !== "lb_ga:bone_golem") return
    let inventory = event.entity.getComponent("inventory")?.container
    let boneMeal = new ItemStack("minecraft:bone_meal", 36)
    inventory.addItem(boneMeal)
})

world.beforeEvents.playerInteractWithEntity.subscribe(event => {
    if (event.target.typeId !== "lb_ga:bone_golem") return
    if (event.player.getComponent("equippable")?.getEquipment("Mainhand")?.typeId === "minecraft:lead") return
    if (compostItems.includes(event.player.getComponent("equippable").getEquipment("Mainhand")?.typeId)) return
    if (event.player.getComponent("equippable").getEquipment("Mainhand")?.typeId === "minecraft:bone_meal") return
    system.run(() => {
        boneForm(event.target).show(event.player)
    })
})

// bedrock uses a 7x5x7 area for bone meal
const crops = ["wheat", "carrots", "potatoes", "torchflower_crop", "pitcher_crop", "beetroot", "melon_stem", "pumpkin_stem"]
function searchArea(location, dimension) {
    const foundBlocks = []
    for (let y = location.y - 2; y <= location.y + 2; y++) {
        if (y < dimension.heightRange.min || y > dimension.heightRange.max) continue
        for (let x = location.x - 3; x <= location.x + 3; x++) {
            for (let z = location.z - 3; z <= location.z + 3; z++) {
                const thisBlock = dimension.getBlock({x:x,y:y,z:z})
                if (thisBlock && crops.includes(thisBlock.typeId.split(":")[1])) { // && crops.includes(thisBlock.typeId)) {
                    if (thisBlock.permutation.getState("growth") < 7) foundBlocks.push(thisBlock)
                }
            }            
        }
    }
    return foundBlocks
}

system.runInterval(() => {
    const dimensions = ["overworld", "nether", "the_end"]
    dimensions.forEach(dimension => {
        dimension = world.getDimension(dimension)
        const entities = dimension.getEntities({ type: "lb_ga:bone_golem" })//.concat(dimension.getEntities({ type: "lb_ga:bone_golem_small" }))
        entities.forEach(entity => {
            const data = boneData(entity)
            if (system.currentTick % data.interval !== 0) return
            if (data.boneMeal.get > 0) {
                const crops = searchArea(entity.location,dimension)
                if (crops.length > 0) {
                    let successes = 0
                    crops.forEach(crop => {
                        // 10% chance to grow each crop
                        if (Math.random() > 0.1) return
                        successes++
                        crop.setPermutation(
                            crop.permutation.withState(
                                "growth",
                                crop.permutation.getState("growth") + 1
                            )
                        )
                        dimension.spawnParticle("minecraft:crop_growth_emitter",crop.bottomCenter())
                    })
                    if (successes > 0) {
                        data.plants.increment()
                        data.boneMeal.decrement()
                    } else sendDebugMessage(`§6INFO§r: bone golem failed all random chance checks; no growth this cycle`)
                }
            }
        })
    })
})