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

// --------------------------------------------------------------------
// Config

// Enable Developer Commands
var conf_debugcommands = true

// Be wary touching anything belowwwwwww
// --------------------------------------------------------------------

// Import subs
import './components.js'
import './scriptevents.js'

// Flask Sound Pitches
let flaskPitchMin = 0.75
let flaskPitchMax = 1.35

// ! Raid Menu Interaction
// !
// !
// !
// !
// !
world.afterEvents.playerInteractWithEntity.subscribe(e => {
    const player = e.player
    const entity = e.target
    if (entity.typeId === 'darkw_onyxdlc1:wave_spawner') {

        let settings = new ModalFormData()
        settings.title('halloween raid')
        settings.dropdown('Difficulty', ['Standard (Easy)', 'Moderate (Medium)', 'Brutal (Hard)', 'Nightmare (Nightmare)'])
        settings.submitButton('Start')
        settings.show(player).then(r => {
            if (r.canceled) return

            let difficulty = ['Standard', 'Moderate', 'Brutal', 'Nightmare']
            let diffSelect = difficulty[r.formValues[0]]

            let confirm = new ActionFormData()
            confirm.title('Confirm')
            confirm.body(`start raid at ${difficulty[r.formValues[0]]} Difficulty?\n\n`)
            confirm.button('Start Raid')
            confirm.button('Cancel')
            confirm.show(player).then(r => {
                if (r.canceled) return
                if (r.selection === 0) {
                    entity.setProperty('darkw_onyxdlc1:difficulty', diffSelect)
                    entity.triggerEvent('darkw_onyxdlc1:menu_remove')
                    entity.triggerEvent('darkw_onyxdlc1:start_raid_event')
                }
            })
        })
    }
})

// ! Vial Controls
// !
// !
// !
// !
// !
world.afterEvents.entityHitBlock.subscribe(ev => {
    if (!ev.damagingEntity.typeId === 'player') return
    let item = ev.damagingEntity.getComponent('equippable').getEquipment('Mainhand')
    if (!item) return
    let entity = ev.damagingEntity
    let block = ev.hitBlock
    switch (item.typeId) {
        // * Kill Vial
        // * -
        // * -
        // * -
        // * -
        // * -
        case "darkw_onyxdlc1:via_kill": {
            if (item.getComponent(ItemComponentTypes.Cooldown).getCooldownTicksRemaining(entity) > 0) return
            let killCount = 0

            let ranPitch = Math.random() * (flaskPitchMax - flaskPitchMin) + flaskPitchMin
            block.dimension.playSound('mob.darkw_onyxdlc1.glassshatter', block.location, {
                pitch: ranPitch
            })
            block.dimension.spawnParticle('darkw_onyxdlc1:vial_kill', { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
            let getMobs = entity.dimension.getEntities({ maxDistance: 5, location: entity.location, families: ['roxcrow'], excludeFamilies: ['roxcrow_boss'] })
            getMobs.splice(3, getMobs.length)
            getMobs.forEach(target => {
                target.runCommand('kill @s')
            })

            // ty come again
            item.getComponent(ItemComponentTypes.Cooldown).startCooldown(entity)
            if (entity.getGameMode() != 'Creative') replaceOnUseOrWhatever(entity, item.amount, item.typeId)
            break
        }
        // * Slow Vial
        // * -
        // * -
        // * -
        // * -
        // * -
        case "darkw_onyxdlc1:via_slow": {
            if (item.getComponent(ItemComponentTypes.Cooldown).getCooldownTicksRemaining(entity) > 0) return

            let ranPitch = Math.random() * (flaskPitchMax - flaskPitchMin) + flaskPitchMin
            block.dimension.playSound('mob.darkw_onyxdlc1.glassshatter', block.location, {
                pitch: ranPitch
            })
            block.dimension.spawnParticle('darkw_onyxdlc1:vial_slow', { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
            let getMobs = entity.dimension.getEntities({ maxDistance: 5, location: entity.location, families: ['roxcrow'], excludeFamilies: ['roxcrow_boss'] })
            getMobs.forEach(target => {
                target.addEffect('slowness', 200, {
                    amplifier: 2,
                    showParticles: true
                })
            })

            // ty come again
            item.getComponent(ItemComponentTypes.Cooldown).startCooldown(entity)
            if (entity.getGameMode() != 'Creative') replaceOnUseOrWhatever(entity, item.amount, item.typeId)
            break
        }
        // * Heal Vial
        // * -
        // * -
        // * -
        // * -
        // * -
        case "darkw_onyxdlc1:via_heal": {
            if (item.getComponent(ItemComponentTypes.Cooldown).getCooldownTicksRemaining(entity) > 0) return

            let ranPitch = Math.random() * (flaskPitchMax - flaskPitchMin) + flaskPitchMin
            block.dimension.playSound('mob.darkw_onyxdlc1.glassshatter', block.location, {
                pitch: ranPitch
            })
            block.dimension.spawnParticle('darkw_onyxdlc1:vial_heal', { x: block.location.x + 0.5, y: block.location.y + 0.5, z: block.location.z + 0.5 })
            let getMobs = entity.dimension.getEntities({ maxDistance: 5, location: entity.location, type: 'player' })
            getMobs.forEach(target => {
                target.addEffect('regeneration', 40, {
                    amplifier: 3,
                    showParticles: true
                })
            })

            // ty come again
            item.getComponent(ItemComponentTypes.Cooldown).startCooldown(entity)
            if (entity.getGameMode() != 'Creative') replaceOnUseOrWhatever(entity, item.amount, item.typeId)
            break
        }
        // * Fire Vial
        // * -
        // * -
        // * -
        // * -
        // * -
        case "darkw_onyxdlc1:via_fire": {
            if (item.getComponent(ItemComponentTypes.Cooldown).getCooldownTicksRemaining(entity) > 0) return

            let ranPitch = Math.random() * (flaskPitchMax - flaskPitchMin) + flaskPitchMin
            block.dimension.playSound('mob.darkw_onyxdlc1.glassshatter', block.location, {
                pitch: ranPitch
            })
            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}`)
                system.runTimeout(() => {
                    block.dimension.playSound('mob.darkw_onyxdlc1.roxcrow.pew', block.location, {
                        volume: 0.15
                    })
                }, 1)
                let spawnSpray = entity.dimension.spawnEntity('darkw_onyxdlc1:firespray', { x: block.location.x + 0.5, y: block.location.y + 1.5, z: block.location.z + 0.5 })
                spawnSpray.applyImpulse({ x: launchX, y: ranSprayY, z: launchZ })
                spawnSpray.getComponent('tameable').tame(entity)
            }

            // ty come again
            item.getComponent(ItemComponentTypes.Cooldown).startCooldown(entity)
            if (entity.getGameMode() != 'Creative') replaceOnUseOrWhatever(entity, item.amount, item.typeId)
            break
        }
    }
})

// ! Entity Hurt
// !
// !
// !
// !
// !
world.afterEvents.entityHurt.subscribe(ev => {
    let target = ev.hurtEntity
    let source = ev.damageSource?.damagingEntity

    if (!source) return
    const equippable = source?.getComponent('equippable')
    if (!equippable) return
    const mainhand = equippable.getEquipment('Mainhand')
    if (!mainhand) return

    if (mainhand.typeId === 'darkw_onyxdlc1:wea_bow1') {
        target.dimension.spawnParticle('darkw_onyxdlc1:vial_kill', { x: target.location.x + 0.5, y: target.location.y + 0.5, z: target.location.z + 0.5 })
        let getMobs = target.dimension.getEntities({ maxDistance: 5, location: target.location, excludeNames: [source.nameTag] })
        getMobs.forEach(aura => {
            aura.addEffect('wither', 40, {
                amplifier: 2,
                showParticles: true
            })
        })
    }
})

// *
// *
// *

// ! Item Use
// !
// !
// !
// !
// !
world.afterEvents.itemUse.subscribe(ev => {
    switch (ev.itemStack.typeId) {
        case "darkw_onyxdlc1:charm_death_no": {
            if (ev.itemStack.getComponent('cooldown').getCooldownTicksRemaining(ev.source) != 0) return
            ev.source.playSound('random.orb')
            ev.source.getComponent('equippable').setEquipment(EquipmentSlot.Mainhand, new ItemStack('darkw_onyxdlc1:charm_death_yes', 1))
            break
        }
    }
})

// ! Entity hurt
// !
// !
// !
// !
// !
world.afterEvents.entityHurt.subscribe(ev => {
    let target = ev.hurtEntity
    let source = ev.damageSource?.damagingEntity


    // Firespray Impact
    if (ev.damageSource.damagingEntity?.typeId === 'darkw_onyxdlc1:firespray') {
        ev.hurtEntity.setOnFire(5)
    }
    // Roxcrow Impact
    if (ev.damageSource.damagingEntity?.typeId === 'darkw_onyxdlc1:roxcrow_a_ally') {
        ev.damageSource?.damagingEntity.triggerEvent('darkw_onyxdlc1:on_despawn_event')
    }

    if (!source) return
    if (source.getComponent('inventory')) {
        let container = source.getComponent('inventory').container
        for (let i = 0; i < container.size; i++) {
            let item = container.getItem(i)
            if (!item) continue
            if (item.typeId === 'darkw_onyxdlc1:charm_death_yes') {
                target.addEffect('wither', 40, {
                    amplifier: 1,
                    showParticles: true
                })
                let ran = Math.floor(Math.random() * 55)
                let dura = item.getComponent('durability')
                if (dura.damage + ran <= dura.maxDurability) {
                    dura.damage += ran
                    container.setItem(i, item)
                }
                if (dura.damage + ran >= dura.maxDurability) {
                    container.setItem(i, new ItemStack('darkw_onyxdlc1:charm_death_no', 1))
                    let replaceCharm = container.getItem(i)
                    let newDura = replaceCharm.getComponent('cooldown').startCooldown(source)

                    source.dimension.spawnParticle('darkw_onyxdlc1:vial_kill', { x: source.location.x, y: source.location.y, z: source.location.z })
                    let getMobs = source.dimension.getEntities({ maxDistance: 5, location: source.location, excludeNames: [source.nameTag] })
                    getMobs.forEach(aura => {
                        aura.addEffect('wither', 40, {
                            amplifier: 2,
                            showParticles: true
                        })
                    })
                }
            }
        }
    }
})

// ! Item Use, used for custom bow(s)
// !
// !
// !
// !
// !
world.afterEvents.itemStartUse.subscribe(ev => {
    const player = ev.source
    const item = ev.itemStack
    switch (item.typeId) {
        case "darkw_onyxdlc1:wea_bow1": {
            player.playAnimation(player.getComponent('equippable').getEquipmentSlot(EquipmentSlot.Offhand).getItem() ? "animation.custom_bow.player.bow.left_item" : "animation.custom_bow.player.bow", { stopExpression: "!q.is_using_item" });
            break
        }
    }
})

// ! Give lore to certain items on world spawn
// !
// !
// !
// !
// !
world.afterEvents.entitySpawn.subscribe(ev => {
    let entity = ev.entity
    if (entity.typeId === 'minecraft:item') {
        let item = entity.getComponent('item').itemStack
        if (item.getLore()[0] != undefined) return
        switch (item.typeId) {
            case "minecraft:dirt": {
                item.setLore(['yurrr'])
                entity.dimension.spawnItem(item, entity.location)
                entity.remove()
            }
            case "darkw_onyxdlc1:via_fire": {
                item.setLore([
                    "\n§r§7Info:\n§r§9 Can be smashed on the ground \n (Melee attack a block) for a desired result.",
                    "§r§7On Ground Smash:",
                    "§r§9 Shoots strands of mini flames out from the block you hit.",
                ]);
                entity.dimension.spawnItem(item, entity.location)
                entity.remove()
                break
            }
            case "darkw_onyxdlc1:via_heal": {
                item.setLore([
                    "\n§r§7Info:\n§r§9 Can be smashed on the ground \n (Melee attack a block) for a desired result.",
                    "§r§7On Ground Smash:",
                    "§r§9 Heals all nearby players around the block you hit.",
                ]);
                entity.dimension.spawnItem(item, entity.location)
                entity.remove()
                break
            }
            case "darkw_onyxdlc1:via_slow": {
                item.setLore([
                    "\n§r§7Info:\n§r§9 Can be smashed on the ground \n (Melee attack a block) for a desired result.",
                    "§r§7On Ground Smash:",
                    "§r§9 Slows down all nearby Roxcrows.",
                ]);
                entity.dimension.spawnItem(item, entity.location)
                entity.remove()
                break
            }
            case "darkw_onyxdlc1:via_kill": {
                item.setLore([
                    "\n§r§7Info:\n§r§9 Can be smashed on the ground \n (Melee attack a block) for a desired result.",
                    "§r§7On Ground Smash:",
                    "§r§9 Kills §eup to three§9 nearby Roxcrows.",
                ]);
                entity.dimension.spawnItem(item, entity.location)
                entity.remove()
                break
            }
        }
    }
})

// * FUNCTIONS
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
// *
function replaceOnUseOrWhatever(entity, amount, typeId) {
    if (amount != 1) {
        entity.runCommand(`/replaceitem entity @s slot.weapon.mainhand 0 ${typeId} ${amount - 1}`)
        return
    }
    if (amount === 1) {
        entity.runCommand(`/replaceitem entity @s slot.weapon.mainhand 0 air 1`)
        return
    }
}

// ! Custom Commands
// !
// !
// !
// !
// !
if (conf_debugcommands) debugCommands()
function debugCommands() {
    system.beforeEvents.startup.subscribe(start => {
        // * Set Wave
        start.customCommandRegistry.registerEnum("onyxdlc1:roxcrow_options", ['spawn', 'eat'])
        start.customCommandRegistry.registerEnum("onyxdlc1:roxcrow_wave", ['Wave 1', 'Wave 2', 'Wave 3', 'Wave 4', 'Wave 5'])
        start.customCommandRegistry.registerCommand({
            // * Command
            name: 'onyxdlc1:roxcrow-setwave',
            description: 'Sets the wave of nearby portals. Number is recommended to be 1 - 6.',
            permissionLevel: CommandPermissionLevel.GameDirectors,
            cheatsRequired: false,
            mandatoryParameters: [
                {
                    name: "wave",
                    type: CustomCommandParamType.Integer
                }
            ]
        }, (r, wave) => {
            let source = r.sourceEntity
            if (!r.sourceEntity) source = r.sourceBlock
    
            let getWaver = source.dimension.getEntities({ maxDistance: 25, families: ['roxcrow_waver'], location: source.location })
    
            // * If no waver, return.
            if (!getWaver) {
                source.runCommand(`/tellraw @s {"rawtext":[{"text":"No number was given to set the portal wave to."}]}`)
                return
            }

            let setWave = parseInt(wave) - 1
    
            if (setWave <= 0 || setWave >= 6) system.run(() => { source.runCommand(`/tellraw @s {"rawtext":[{"text":"§cGiven number must be from 1 - 6."}]}`)})
            if (setWave <= 0 || setWave >= 6) return

            if (getWaver.length === 0) system.run(() => { source.runCommand(`/tellraw @s {"rawtext":[{"text":"§cNo portals found nearby."}]}`) })
            if (getWaver.length > 0) system.run(() => { source.runCommand(`/tellraw @s {"rawtext":[{"text":"Set nearby portals to wave ${setWave + 1}."}]}`) })
            getWaver.forEach(waver => {
                system.run(() => {
                    waver.setProperty('darkw_onyxdlc1:wave', setWave)
                    waver.runCommand('kill @s')
                })
            })
        })
    })
}