import { system, world, BlockVolume, EquipmentSlot, ItemComponentTypes, ItemStack } from '@minecraft/server'
import { CommandPermissionLevel, CustomCommandParamType, CustomCommandStatus } from "@minecraft/server";
import { ActionFormData, ModalFormData } from '@minecraft/server-ui'

// ! Script Events
system.afterEvents.scriptEventReceive.subscribe(e => {
    const id = e.id
    const entity = e.sourceEntity ? e.sourceEntity : e.sourceBlock
    const location = entity.location
    if (!location) return
    const msg = e.message

    switch (id) {
        // * Firecrow Death Event
        case "darkw_onyxdlc1:start_menu": {
            const player = entity
            const block = e.sourceBlock

            break
        }
        // * Random Fire Spray
        case "darkw_onyxdlc1:spawn_fire_spray": {
            const player = entity
            const block = e.sourceBlock

            for (let i = 0; i != 15; i++) {
                let posNeg1 = Math.random() <= 0.5 ? '+' : '-'
                let posNeg2 = Math.random() <= 0.5 ? '+' : '-'
                let ranSprayX = Math.random()
                let ranSprayZ = Math.random()
                let ranSprayY = Math.random()

                let launchX = parseFloat(`${posNeg1}${ranSprayX}`)
                let launchZ = parseFloat(`${posNeg2}${ranSprayZ}`)
                entity.dimension.spawnEntity('darkw_onyxdlc1:firespray', {x: entity.location.x, y: entity.location.y + 1, z: entity.location.z}).applyImpulse({x: launchX, y: ranSprayY, z: launchZ})
            }


            break
        }
        // * Random Loot Spray
        case "darkw_onyxdlc1:ranInpulse": {
            const player = entity
            const block = e.sourceBlock

            for (let i = 0; i != 15; i++) {
                let posNeg1 = Math.random() <= 0.5 ? '+' : '-'
                let posNeg2 = Math.random() <= 0.5 ? '+' : '-'
                let ranSprayX = Math.random() * 3
                let ranSprayZ = Math.random() * 3
                let ranSprayY = Math.random()

                let launchX = parseFloat(`${posNeg1}${ranSprayX}`)
                let launchZ = parseFloat(`${posNeg2}${ranSprayZ}`)
                entity.applyImpulse({x: launchX, y: ranSprayY, z: launchZ})
            }


            break
        }
        case "darkw_onyxdlc1:endless_mode_buff_tick": {
            let reLoot = entity.getProperty('darkw_onyxdlc1:rebirth')
            let mobs = entity.dimension.getEntities({ maxDistance: 18, families: ['roxcrow'], location: location, excludeTypes: ['minecraft:item'] })

            if (reLoot === 0) return
            mobs.forEach(mob => {
                mob.addEffect('health_boost', 200, {amplifier: reLoot, showParticles: false})

                if (!mob.hasTag('darkw_onyxdlc1:has_been_blessed')) {
                    let health = mob.getComponent('health')
                    health.setCurrentValue(health.effectiveMax)
                    mob.addTag('darkw_onyxdlc1:has_been_blessed')
                    
                }
            })
            break
        }
        case "darkw_onyxdlc1:loot_spray_normal": {
            const player = entity
            const block = e.sourceBlock
            let reLoot = entity.getProperty('darkw_onyxdlc1:rebirth')
            const ran = 4

            // Normal Mode loot spray
            for (let i = 0; i != ran; i++) {
                entity.dimension.spawnEntity('darkw_onyxdlc1:wave_reward', {x: entity.location.x, y: entity.location.y + 1, z: entity.location.z}).setProperty('darkw_onyxdlc1:difficulty', entity.getProperty('darkw_onyxdlc1:difficulty'))
            }
            if (reLoot === 0) return
            // Endless Mode bonus spray
            for (let i = 0; i != reLoot; i++) {
                entity.dimension.spawnEntity('darkw_onyxdlc1:wave_reward', {x: entity.location.x, y: entity.location.y + 1, z: entity.location.z}).setProperty('darkw_onyxdlc1:difficulty', entity.getProperty('darkw_onyxdlc1:difficulty'))
            }


            break
        }
        case "darkw_onyxdlc1:loot_poof": {
            const player = entity
            const block = e.sourceBlock
            const ran = Math.floor(Math.random() * 6)
            const difficulty = entity.getProperty('darkw_onyxdlc1:difficulty')
            entity.dimension.spawnParticle('darkw_onyxdlc1:loot_poof', entity.location)

            switch (difficulty) {
                case "Standard": {
                    entity.runCommand('/loot spawn ~0.5 ~ ~0.5 loot "darkw/onyxdlc1/rewards/standard"')
                    break
                }
                case "Moderate": {
                    entity.runCommand('/loot spawn ~0.5 ~ ~0.5 loot "darkw/onyxdlc1/rewards/moderate"')
                    break
                }
                case "Brutal": {
                    entity.runCommand('/loot spawn ~0.5 ~ ~0.5 loot "darkw/onyxdlc1/rewards/brutal"')
                    break
                }
                case "Nightmare": {
                    entity.runCommand('/loot spawn ~0.5 ~ ~0.5 loot "darkw/onyxdlc1/rewards/nightmare"')
                    break
                }
            }


            break
        }
        // * Firecrow Death Event
        case "darkw_onyxdlc1:spawn_wave": {
            switch (entity.getProperty('darkw_onyxdlc1:type')) {
                case "Normal": {
                    let spawnRaid = entity.dimension.spawnEntity('darkw_onyxdlc1:wave_spawner', {x: entity.location.x, y: entity.location.y + 2, z: entity.location.z})
                    spawnRaid.setProperty('darkw_onyxdlc1:difficulty', entity.getProperty('darkw_onyxdlc1:difficulty'))
                    entity.remove()
                    break
                }
                case "Endless": {
                    let spawnRaid = entity.dimension.spawnEntity('darkw_onyxdlc1:wave_spawner_endless', {x: entity.location.x, y: entity.location.y + 2, z: entity.location.z})
                    spawnRaid.setProperty('darkw_onyxdlc1:difficulty', entity.getProperty('darkw_onyxdlc1:difficulty'))
                    entity.remove()
                    break
                }
            }
            break
        }
        case "darkw_onyxdlc1:roxcrowB_death_event": {
            let mobs = entity.dimension.getEntities({ maxDistance: 5, excludeFamilies: ['roxcrow'], location: location, excludeTypes: ['minecraft:item'] })
            mobs.forEach(mob => {
                let shTest1 = mob.runCommand('/testfor @s[hasitem={item=minecraft:shield, location=slot.weapon.mainhand}]').successCount
                let shTest2 = mob.runCommand('/testfor @s[hasitem={item=minecraft:shield, location=slot.weapon.offhand}]').successCount
                if ((shTest1 === 0 || shTest2 === 0) && !mob.isSneaking) {
                    mob.setOnFire(3)
                    mob.applyDamage(6, {
                        cause: 'entity_attack',
                        damagingProjectile: entity,
                        damagingEntity: entity
                    })
                }
            })
            break
        }
        // * Etterbeast Fang Damage on bite.
        case "darkw_onyxdlc1:roxcrowZ_beast_nom": {
            let owner = entity.getComponent('tameable').tamedToPlayer === undefined ? 'undefined' : entity.getComponent('tameable').tamedToPlayer.nameTag
            let mobs = entity.dimension.getEntities({ maxDistance: 1, excludeFamilies: ['roxcrow'], location: location, excludeNames: [owner]})
            mobs.forEach(mob => {
                let shTest1 = mob.runCommand('/testfor @s[hasitem={item=minecraft:shield, location=slot.weapon.mainhand}]').successCount
                let shTest2 = mob.runCommand('/testfor @s[hasitem={item=minecraft:shield, location=slot.weapon.offhand}]').successCount
                if ((shTest1 === 0 || shTest2 === 0) && !mob.isSneaking && mob.typeId != 'minecraft:item') {
                    mob.applyDamage(12, {
                        cause: 'entity_attack',
                        damagingProjectile: entity,
                        damagingEntity: entity
                    })
                }
            })
            break
        }
        // * Lookcrow Stare Event, Health on Tick on look
        case "darkw_onyxdlc1:roxcrowC_looktick": {
            let health = entity.getComponent('health')
            if (health.currentValue <= 1) {
                entity.runCommand('kill @s')
            }
            if (health.currentValue > 1) {
                health.setCurrentValue(health.currentValue - 1)
            }
            break
        }
        // * Even used on tick to heal the Pylon between waves.
        case "darkw_onyxdlc1:wave_spawner-regen": {
            let health = entity.getComponent('health')
            let regen = 25
            if (health.currentValue != 1000 && health.currentValue + regen <= 1000) {
                health.setCurrentValue(health.currentValue + regen)
            }
            if (health.currentValue != 1000 && health.currentValue + regen >= 1000) {
                health.setCurrentValue(1000)
            }
            break
        }
        // * Debug, Sets Pylon health to 1 and autocompletes wave.
        case "darkw_onyxdlc1:wave_spawner-debug_completeWave_no": {
            let health = entity.getComponent('health')
            health.setCurrentValue(1)
            break
        }
        // * Debug, Sets Pylon health to 1 and autocompletes wave.
        case "darkw_onyxdlc1:wave_spawner-debug_completeWave": {
            if (entity.getProperty('darkw_onyxdlc1:can_spawn_mobs') === false) return
            let health = entity.getComponent('health')
            health.setCurrentValue(1)
            break
        }
        // * On wave entity kill, The 'Pylon' takes damage
        case "darkw_onyxdlc1:wave_spawner-onMobKill": {
            if (entity.getProperty('darkw_onyxdlc1:can_spawn_mobs') === false) return
            try {
                let ranDam = Math.floor(Math.random() * 100)
                let health = entity.getComponent('health')
                if (health.currentValue - ranDam <= 1) {
                    health.setCurrentValue(1)
                }
                if (health.currentValue - ranDam >= 1) {
                    health.setCurrentValue(health.currentValue - ranDam)
                }
                break
            }
            catch {}
        }
        // * Wave Spawn
        case "darkw_onyxdlc1:wave_spawner-spawn_entity": {
            let wav = entity.getProperty('darkw_onyxdlc1:wave')

            entity.runCommand(`scriptevent darkw_onyxdlc1:spawn_wave_entity ${JSON.stringify(wav)}`)
            break
        }
        // * Wave Bars
        case "darkw_onyxdlc1:wave_spawner-increment_wave": {
            const getPlayers = entity.dimension.getEntities({maxDistance: 25, type: 'minecraft:player', location: entity.location})
            const delayTimes = '10 45 60'
            entity.dimension.playSound('raid.horn', entity.location, {
                volume: 0.25,
                pitch: 0.95
            })
            system.runTimeout(() => {
                switch (entity.getProperty('darkw_onyxdlc1:wave')) {
                    // * Wave 1
                    case 1: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Wave 1')
                            player.runCommand('/title @s subtitle R0X-SSRRa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_wave1')
                        break
                    }
                    // * Wave 2
                    case 2: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Wave 2')
                            player.runCommand('/title @s subtitle R0X-SSRRa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_wave2')
                        break
                    }
                    // * Wave 3
                    case 3: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Wave 3')
                            player.runCommand('/title @s subtitle R0X-SSRRa, R0X-SLAa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_wave3')
                        break
                    }
                    // * Wave 4
                    case 4: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Wave 4')
                            player.runCommand('/title @s subtitle R0X-SSRRa, DEPR0Xa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_wave4')
                        break
                    }
                    // * Wave 5
                    case 5: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Wave 5')
                            player.runCommand('/title @s subtitle R0X-SSRRa, R0X-SLAa, DEPR0Xa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_wave5')
                        break
                    }
                    // * Wave 6
                    case 6: {
                        getPlayers.forEach(player => {
                            player.runCommand(`/title @s times ${delayTimes}`)
                            player.runCommand('/title @s title Boss Wave')
                            player.runCommand('/title @s subtitle 3TT3RCR0Xa, R0X-SSRRa, R0X-SLAa, DEPR0Xa')
                            player.runCommand('/title @s reset')
                        })
                        entity.triggerEvent('darkw_onyxdlc1:bar_remove')

                                    let cordsList = []
                        // & Location Magic
                        const loc = entity.location
                        const bv = new BlockVolume(
                            { x: loc.x + 7, y: loc.y + 7, z: loc.z + 7 },
                            { x: loc.x - 7, y: loc.y - 3, z: loc.z - 7 }
                        )

                        // & Block Testing Magic
                        const hits = entity.dimension.getBlocks(bv, { excludeTypes: ['minecraft:air'] })
                        for (let cords of hits.getBlockLocationIterator()) {
                            const block = entity.dimension.getBlock(cords)
                            if (block.above(1).typeId != 'minecraft:air') continue
                            cordsList.push(cords)
                        }
                        let ran = Math.floor(Math.random() * cordsList.length)
                        let ranCord = cordsList[ran]

                        const spawnBlock = entity.dimension.getBlock(ranCord)
                        let spawE = spawnBlock.dimension.spawnEntity('darkw_onyxdlc1:roxcrow_z', { x: spawnBlock.location.x, y: spawnBlock.location.y + 0.5, z: spawnBlock.location.z })
                        spawE.addTag(`darkw_onyxdlc1:difftag-${entity.getProperty('darkw_onyxdlc1:difficulty')}`)
                        break
                    }
                    case 7: {
                        break
                    }
                }
            })
            break
        }
        // * Complete The Raid
        case "darkw_onyxdlc1:wave_spawner-complete_raid": {
            entity.remove()
            break
        }
        // * Complete The Current Wave
        case "darkw_onyxdlc1:wave_spawner-complete_wave": {
            entity.dimension.getEntities({ maxDistance: 35, families: ['roxcrow'], excludeFamilies: ['roxcrow_boss'], location: entity.location }).forEach(mob => {
                mob.runCommand('kill @s')
            })
            break
        }
        // * A Roxcrow is killed
        case "darkw_onyxdlc1:wave_spawner-roxcrow_killed": {
            if (entity.typeId.includes('ally')) return
            system.runTimeout(() => {
                entity.runCommand('/loot spawn ~0.5 ~ ~0.5 loot "darkw/onyxdlc1/roxcrow"')
            }, 10)
            entity.dimension.getEntities({ maxDistance: 17, families: ['roxcrow_waver'], excludeFamilies: ['roxcrow_boss'], location: entity.location }).forEach(mob => {
                if (mob.getProperty('darkw_onyxdlc1:wave') === 6) return
                mob.runCommand('scriptevent darkw_onyxdlc1:wave_spawner-onMobKill')
            })
            break
        }
        // * Wave 6 boss is killed
        case "darkw_onyxdlc1:wave_spawner-boss_killed": {
            entity.dimension.getEntities({ maxDistance: 17, families: ['roxcrow_waver'], excludeFamilies: ['roxcrow_boss'], location: entity.location }).forEach(mob => {
                mob.runCommand('scriptevent darkw_onyxdlc1:wave_spawner-debug_completeWave')
            })
            entity.remove()
            break
        }
        // * Wave 6 boss is killed
        case "darkw_onyxdlc1:despawn": {
            entity.remove()
            break
        }
        // * Roxcrow Overflow, event for one needs to be removed
        case "darkw_onyxdlc1:wave_spawner-roxcrow_despawn": {
            entity.remove()
            break
        }
        // & ----------------------------------
        // &           SPAWN EVENT
        // & ----------------------------------
        case "darkw_onyxdlc1:spawn_wave_entity": {
            if (!entity.getProperty('darkw_onyxdlc1:can_spawn_mobs')) return
            let cordsList = []
            let waveOneIds = [
                'darkw_onyxdlc1:roxcrow_a'
            ]
            let waveTwoIds = [
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_b'
            ]
            let waveThreeIds = [
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_c'
            ]
            let waveFiveIds = [
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_a',
                'darkw_onyxdlc1:roxcrow_b',
                'darkw_onyxdlc1:roxcrow_b',
                'darkw_onyxdlc1:roxcrow_c'
            ]

            // & Location Magic
            const loc = entity.location
            const bv = new BlockVolume(
                { x: loc.x + 7, y: loc.y + 7, z: loc.z + 7 },
                { x: loc.x - 7, y: loc.y - 3, z: loc.z - 7 }
            )

            // & Block Testing Magic
            const hits = entity.dimension.getBlocks(bv, { excludeTypes: ['minecraft:air'] })
            for (let cords of hits.getBlockLocationIterator()) {
                const block = entity.dimension.getBlock(cords)
                if (block.above(1).typeId != 'minecraft:air') continue
                cordsList.push(cords)
            }

            let spawnentityId = ""
            if (!msg) console.warn('§eNo wave number given.')
            else {
                // & Test for Wave
                switch (msg) {
                    case '1': {
                        spawnentityId = waveOneIds[Math.floor(Math.random() * waveOneIds.length)]
                        break
                    }
                    case '2': {
                        spawnentityId = waveOneIds[Math.floor(Math.random() * waveOneIds.length)]
                        break
                    }
                    case '3': {
                        spawnentityId = waveTwoIds[Math.floor(Math.random() * waveTwoIds.length)]
                        break
                    }
                    case '4': {
                        spawnentityId = waveThreeIds[Math.floor(Math.random() * waveThreeIds.length)]
                        break
                    }
                    case '5': {
                        spawnentityId = waveFiveIds[Math.floor(Math.random() * waveFiveIds.length)]
                        break
                    }
                    case '6': {
                        spawnentityId = waveFiveIds[Math.floor(Math.random() * waveFiveIds.length)]
                        break
                    }
                    case 'boss': {
                        spawnentityId = 'darkw_onyxdlc1:roxcrow_z'
                        break
                    }
                }

                                        // Is Wave 6?
                        let ranSpawn = Math.floor(Math.random() * 5)
                        if (ranSpawn <= 1 && entity.getProperty('darkw_onyxdlc1:wave') === 6) return


                // * Spawn
                let ran = Math.floor(Math.random() * cordsList.length)
                let ranCord = cordsList[ran]

                let roxCount = entity.dimension.getEntities({ location: entity.location, families: ['roxcrow'], maxDistance: 30 })
                let overflow = entity.dimension.getEntities({ location: entity.location, families: ['roxcrow'], maxDistance: 30, minDistance: 17 })
                
                if (roxCount.length > 12) return
                const spawnBlock = entity.dimension.getBlock(ranCord)
                let spawE = spawnBlock.dimension.spawnEntity(spawnentityId, { x: spawnBlock.location.x, y: spawnBlock.location.y + 0.5, z: spawnBlock.location.z })
                spawE.addTag(`darkw_onyxdlc1:difftag-${entity.getProperty('darkw_onyxdlc1:difficulty')}`)


                return
                overflow.forEach(mob => {
                    mob.triggerEvent('darkw_onyxdlc1:on_despawn_event')
                })

                if (roxCount.length > 12) {
                    let ranMob = Math.floor(Math.random() * roxCount.length)
                    if (roxCount[ranMob].typeId === 'darkw_onyxdlc1:roxcrow_z') return
                    roxCount[ranMob].triggerEvent('darkw_onyxdlc1:on_despawn_event')
                }
            }
            break
        }
    }
})