import { system, world, EntityComponentTypes, ItemStack, EquipmentSlot } from '@minecraft/server'
import { captureChicken } from 'ds/mch/item/capture_net.js'
import { snapRotation } from 'ds/mch/entity/entity.js'
import { setAllowCapture } from 'ds/mch/entity/chicken.js'
import { getRandomInt } from 'ds/mch/utils/math.js'
import { chickens } from 'ds/mch/data/chickens.js'
import { particle_id } from 'ds/mch/data/particle_id.js'

const FAIL_RATE = {
    common: 0.1,
    uncommon: 0.2,
    rare: 0.3,
    super_rare: 0.4
}

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

    if (entity.typeId === 'ds_mc:chicken_breeder') {
        snapRotation(entity)

        entity.runCommand(`ride @s summon_rider ds_mc:chicken_breeder_right`)
        entity.runCommand(`ride @s summon_rider ds_mc:chicken_breeder_left`)
    }
})

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

    if (removedEntity.typeId === 'ds_mc:chicken_breeder') {
        let riders = getRiders(removedEntity)

        system.run(() => {
            for (let rider of riders) {
                rider.remove()
            }
        })
    }
})

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

    if (target.typeId === 'ds_mc:chicken_breeder_left' || target.typeId === 'ds_mc:chicken_breeder_right') {
        let rideableComponent = target.getComponent(EntityComponentTypes.Rideable)

        if (rideableComponent.getRiders().length == 0) {
            //no riders yet (place chicken)
            let chickenId = undefined
            if (itemStack) {
                if (itemStack.getTags().includes('ds_mc:captured_chicken')) {
                    chickenId = itemStack.typeId.replace('_captured', '')
                }
            }

            if (chickenId) {
                placeChicken(player, target, chickenId)
            }
        } else {
            //remove chicken
            const chicken = getRiders(target)[0]
            captureChicken(chicken, player, itemStack)
        }

        const ridingComponent = target.getComponent(EntityComponentTypes.Riding)
        if (ridingComponent) {
            updatePreview(ridingComponent.entityRidingOn)
        }
    }

    if (target.typeId === 'ds_mc:chicken_breeder') {
        target.playAnimation('animation.ds_mc.chicken_breeder.button')

        let riders = getRiders(target)

        if (riders.length > 2) {
            //breeding done
            const chicken = riders[2]
            captureChicken(chicken, player, itemStack)
        } else {
            breed(target)
        }
    }
})

const breedOptionsMapL = new Map()
const breedOptionsMapR = new Map()
const resultOptionsMap = new Map()
let index = 0

//Cycle options
system.runInterval(() => {
    breedOptionsMapL.forEach((value, entity) => {
        entity.setProperty('ds_mc:particle_r', particle_id[value[index]])
    })

    breedOptionsMapR.forEach((value, entity) => {
        entity.setProperty('ds_mc:particle_l', particle_id[value[index]])
    })

    resultOptionsMap.forEach((value, entity) => {
        entity.setProperty('ds_mc:particle_t', particle_id[value[index]])
    })

    index++
    if (index > 1) index = 0
}, 20)

function updatePreview(entity) {
    entity.setProperty('ds_mc:particle_l', 0)
    entity.setProperty('ds_mc:particle_r', 0)
    entity.setProperty('ds_mc:particle_t', 0)

    breedOptionsMapL.delete(entity)
    breedOptionsMapR.delete(entity)
    resultOptionsMap.delete(entity)

    const riders = getRiders(entity)

    const chicken_l = getRiders(riders[0])[0]
    const chicken_r = getRiders(riders[1])[0]

    if (chicken_l && chicken_r) {
        let chicken_name_l = chicken_l.typeId.replace('ds_mc:', '')
        let chicken_name_r = chicken_r.typeId.replace('ds_mc:', '')

        entity.setProperty('ds_mc:particle_l', particle_id[chicken_name_l])
        entity.setProperty('ds_mc:particle_r', particle_id[chicken_name_r])

        if (chickens[chicken_name_l].breed.includes(chicken_name_r)) {
            let results = chickens[chicken_name_l].result
            if (results.length == 1) {
                entity.setProperty('ds_mc:particle_t', particle_id[results[0]])
            } else {
                resultOptionsMap.set(entity, results)
            }
        } else {
            entity.setProperty('ds_mc:particle_t', 101)
        }
    } else if (chicken_l) {
        entity.setProperty('ds_mc:particle_t', 0)
        resultOptionsMap.delete(entity)

        let chicken_name = chicken_l.typeId.replace('ds_mc:', '')
        let id = particle_id[chicken_name]
        entity.setProperty('ds_mc:particle_l', id)

        let breedOptions = chickens[chicken_name].breed
        if (breedOptions.length === 1) {
            entity.setProperty('ds_mc:particle_r', particle_id[breedOptions[0]])
        } else {
            breedOptionsMapL.set(entity, breedOptions)
        }
    } else if (chicken_r) {
        entity.setProperty('ds_mc:particle_t', 0)
        resultOptionsMap.delete(entity)

        let chicken_name = chicken_r.typeId.replace('ds_mc:', '')
        let id = particle_id[chicken_name]
        entity.setProperty('ds_mc:particle_r', id)

        let breedOptions = chickens[chicken_name].breed
        if (breedOptions.length === 1) {
            entity.setProperty('ds_mc:particle_l', particle_id[breedOptions[0]])
        } else {
            breedOptionsMapR.set(entity, breedOptions)
        }
    }
}

function breed(breeder) {
    let chicken1 = undefined
    let chicken2 = undefined

    //set chicken names
    getRiders(breeder).forEach((rider, index) => {
        let rideableComponent = rider.getComponent(EntityComponentTypes.Rideable)
        if (rideableComponent) {
            if (rideableComponent.getRiders().length === 1) {
                const chicken = rideableComponent.getRiders()[0]
                const typeId = chicken.typeId
                const name = getChickenName(typeId)

                if (index === 0) {
                    chicken1 = name
                } else {
                    chicken2 = name
                }

                setAllowCapture(chicken, false)
            }
        }
    })

    //breed
    if (!chicken1 || !chicken2) return
    if (!isBreedable(chicken1, chicken2)) {
        breeder.dimension.playSound('note.pling', breeder.location, { pitch: 0.2 })
        return
    }

    let results = chickens[chicken1].result

    let result = undefined
    if (results.length > 1) {
        const randomInt = getRandomInt(0, results.length - 1)
        result = results[randomInt]
    } else {
        result = results[0]
    }

    for (let rider of getRiders(breeder)) {
        rider.playAnimation('animation.ds_mc.chicken_breeder.breed')
        rider.setProperty('ds_mc:breeding', true)
    }

    breeder.playAnimation('animation.ds_mc.chicken_breeder.breed')

    //after animation
    system.runTimeout(() => {
        const rarity = chickens[chicken1].rarity
        const chance = FAIL_RATE[rarity]
        const random = Math.random()

        if (random <= chance) {
            breedFail(breeder)
        } else {
            breedSucces(breeder, result)
        }

        updatePreview(breeder)
    }, 77)
}

function breedSucces(breeder, result) {
    breeder.runCommand(`ride @s summon_rider ds_mc:${result}`)

    for (let rider of getRiders(breeder)) {
        let rideableComponent = rider.getComponent(EntityComponentTypes.Rideable)
        if (rideableComponent) {
            rideableComponent.getRiders()[0].remove()
        }

        if (rider.getProperty('ds_mc:breeding') != undefined) {
            rider.setProperty('ds_mc:breeding', false)
        }
    }

    breeder.dimension.spawnEntity('ds_mc:machine_success_particle',
        {
            x: breeder.location.x,
            y: breeder.location.y + 4,
            z: breeder.location.z
        }
    )
}

function breedFail(breeder) {
    //remove random chicken
    const randomChicken = getRandomInt(0, 1)
    let riders = getRiders(breeder)
    riders[randomChicken].getComponent(EntityComponentTypes.Rideable).getRiders()[0].remove()

    for (let rider of riders) {
        if (rider.getProperty('ds_mc:breeding') != undefined) {
            rider.setProperty('ds_mc:breeding', false)
        }

        if (rider.getComponent(EntityComponentTypes.Rideable).getRiders().length) {
            setAllowCapture(rider.getComponent(EntityComponentTypes.Rideable).getRiders()[0], true)
        }
    }

    breeder.dimension.spawnEntity('ds_mc:machine_fail_particle',
        {
            x: breeder.location.x,
            y: breeder.location.y + 4,
            z: breeder.location.z
        }
    )
}

function getChickenName(typeId) {
    return typeId.replaceAll('ds_mc:', '').replaceAll('_captured', '')
}

export function placeChicken(player, target, chickenId) {
    let equipmentComponent = player.getComponent(EntityComponentTypes.Equippable)
    if (equipmentComponent) {
        const item = new ItemStack('ds_mc:capture_net', 1)
        equipmentComponent.setEquipment(EquipmentSlot.Mainhand, item);
    }

    target.runCommand(`ride @s summon_rider ${chickenId}`)
}

export function getRiders(entity) {
    let rideableComponent = entity.getComponent(EntityComponentTypes.Rideable)

    if (rideableComponent) {
        return rideableComponent.getRiders()
    }
}

function isBreedable(chicken1, chicken2) {
    let breedables = chickens[chicken1].breed

    for (let breedable of breedables) {
        if (chicken2 === breedable) {
            return true
        }
    }
    return false
}