import { system, world, ItemStack, BlockComponentTypes } from '@minecraft/server'
import { snapRotation } from 'ds/mch/entity/entity.js'
import { removeItemFromHand, getAmountFromHand } from 'ds/mch/player/player.js'
import { chickens } from 'ds/mch/data/chickens.js'
import { getAllEntities } from 'ds/mch/world/world.js'

const MAX_FUEL = 10
const MAX_EGGS = 64

//spawn
world.afterEvents.entitySpawn.subscribe(event => {
    const entity = event.entity

    if (entity.typeId === 'ds_mc:egg_processor') {
        snapRotation(entity)
        updateAmount(entity)
    }
})

//despawn
world.beforeEvents.entityRemove.subscribe(event => {
    const { removedEntity } = event

    if (removedEntity.typeId === 'ds_mc:egg_processor') {
        const dimension = removedEntity.dimension
        const location = removedEntity.location

        for (let egg of getEggs(removedEntity)) {
            const item = new ItemStack(egg, 1)

            system.run(() => {
                dimension.spawnItem(item, location)
            })
        }

        const fuelAmount = getFuel(removedEntity)
        if (fuelAmount) {
            system.run(() => {
                dimension.spawnItem(new ItemStack('minecraft:redstone', fuelAmount), location)
            })
        }
    }
})

world.afterEvents.playerInteractWithEntity.subscribe(event => {
    const { player, target, itemStack } = event

    if (target.typeId === 'ds_mc:egg_processor') {
        if (itemStack) {
            if (itemStack.typeId === 'minecraft:redstone') {
                if (player.isSneaking) {
                    increaseFuel(target, player, itemStack.amount)
                } else {
                    increaseFuel(target, player, 1)
                }
            } else if (itemStack.getTags().includes('ds_mc:egg')) {
                if (player.isSneaking) {
                    let amount = itemStack.amount

                    while (amount > 0) {
                        if (getEggs(target).length < MAX_EGGS) {
                            addEgg(target, itemStack.typeId)
                            removeItemFromHand(player)
                        }
                        amount--
                    }
                } else {
                    if (getEggs(target).length < MAX_EGGS) {
                        addEgg(target, itemStack.typeId)
                        removeItemFromHand(player)
                    }
                }
            } else {
                toggleMachine(target)
            }
        } else {
            toggleMachine(target)
        }
    }
})

function toggleMachine(entity) {
    entity.setProperty('ds_mc:on', !entity.getProperty('ds_mc:on'))
}

function turnOff(entity) {
    entity.setProperty('ds_mc:on', false)
}

system.runInterval(() => {
    getAllEntities('ds_mc:egg_processor').forEach(entity => {
        process(entity, 5)
    })
}, 100)

function process(entity, amount) {
    if (entity.getProperty('ds_mc:on') === false) return

    if (getFuel(entity) === 0) {
        turnOff(entity)
        return
    }

    for (let i = 0; i < amount; i++) {
        const egg = getFirstEgg(entity)
        if (!egg) {
            turnOff(entity)
        } else {
            entity.playAnimation('animation.ds_mc.egg_processor.processing')
            decreaseFuel(entity)
            removeFirstEgg(entity)

            system.runTimeout(() => {
                const item = new ItemStack(getItem(egg), 1)
                const entityViewDirection = entity.getViewDirection()
                const entityLocation = entity.location

                if (!placeItemInChest(entity, entityLocation, entityViewDirection, item)) {
                    entity.dimension.spawnItem(item,
                        {
                            x: entityLocation.x + (entityViewDirection.x * 2),
                            y: entityLocation.y + 0.5,
                            z: entityLocation.z + (entityViewDirection.z * 2)
                        }
                    )
                }
            }, 60)
        }
    }
}

function placeItemInChest(entity, entityLocation, entityViewDirection, item) {
    const block = entity.dimension.getBlock(
        {
            x: entityLocation.x + (entityViewDirection.x * 2),
            y: entityLocation.y,
            z: entityLocation.z + (entityViewDirection.z * 2)
        }
    )

    if (!block) return false
    if (block.typeId != 'minecraft:chest') return false

    let inventory = block.getComponent(BlockComponentTypes.Inventory)
    if (!inventory || !inventory.container) return false
    if (inventory.container.emptySlotsCount === 0) return false

    inventory.container.addItem(item)

    return true
}

function getFuel(entity) {
    return entity.getProperty('ds_mc:fuel')
}

function increaseFuel(entity, player, amount) {
    let current_fuel = entity.getProperty('ds_mc:fuel')

    while (amount > 0) {
        const itemAmount = getAmountFromHand(player)

        if (itemAmount > 0) {
            if (current_fuel < MAX_FUEL) {
                removeItemFromHand(player)
                current_fuel++
            }
        }

        amount--
    }

    entity.setProperty('ds_mc:fuel', current_fuel)
}

function decreaseFuel(entity) {
    const current_fuel = entity.getProperty('ds_mc:fuel')

    if (current_fuel > 0) {
        entity.setProperty('ds_mc:fuel', current_fuel - 1)
    }
}

function getEggs(entity) {
    const eggs = entity.getDynamicProperty('eggs')

    if (eggs) {
        return eggs.split(';')
    } else {
        return []
    }
}

function getFirstEgg(entity) {
    const eggs = entity.getDynamicProperty('eggs')

    if (eggs) {
        return eggs.split(';')[0]
    } else {
        return undefined
    }
}

function addEgg(entity, egg) {
    let eggs = entity.getDynamicProperty('eggs')

    if (eggs) {
        let array = eggs.split(';')
        array.push(egg)
        eggs = array.join(';')
    } else {
        eggs = `${egg}`
    }

    entity.setDynamicProperty('eggs', eggs)
    updateAmount(entity)
}

function removeFirstEgg(entity) {
    let eggs = entity.getDynamicProperty('eggs')

    if (eggs) {
        let array = eggs.split(';')
        array.shift()
        eggs = array.join(';')
    } else {
        eggs = ''
    }

    entity.setDynamicProperty('eggs', eggs)
    updateAmount(entity)
}

function getItem(egg) {
    const chickenName = egg.replace('ds_mc:', '').replace('_egg', '')
    return chickens[chickenName].drop
}

function updateAmount(entity) {
    const amount = getEggs(entity).length
    entity.setProperty('ds_mc:egg_amount', amount)
}