import * as mc from '@minecraft/server';
import * as lib from '../lib/lib';
import * as config from '../pb_scraft_config';

import { deleteProjectile, registerProjectile } from '../lib/projectile_tracker';
import { SPELL_PLAYERS } from '../pb_scraft_player';


export default class SpellHoldProjectile {

    player;
    cooldown;
    name;
    manacost;
    castTime;
    soundCast;
    projectileData;

    timeIndex = 0;
    isCharged = false;
    isActive = true;
    itemUse;

    totalTime;

    glyphPower = 0;

    constructor(player, spellData, itemUse) {
        this.player = player;
        this.itemUse = itemUse;

        this.name = spellData.identifier;
        this.manacost = spellData.manacost;;
        this.castTime = spellData.castTime;;
        this.cooldown = spellData.cooldown;
        this.soundCast = spellData.soundCast;
        this.projectileData = config.EFFECT_LIST.find((f) => f.identifier == spellData.projectile);

        this.totalTime = this.castTime + this.cooldown;

        this.processItem(itemUse, spellData)
    }

    processItem(itemUse, spelldata) {
        const glyph_1 = itemUse.getDynamicProperty("pb_scraft_glyph_1");
        const glyph_2 = itemUse.getDynamicProperty("pb_scraft_glyph_2");

        let glyphMana = 1.0;
        let glyphCastTime = 1.0;

        if (glyph_1 != undefined) {
            if (glyph_1 == "pb_scraft:glyph_accelerate") glyphCastTime = glyphCastTime - 0.3;
            if (glyph_1 == "pb_scraft:glyph_alleviate") glyphMana = glyphMana - 0.2;
            if (glyph_1 == "pb_scraft:glyph_intensify") this.glyphPower = this.glyphPower + 10;
        }

        if (glyph_2 != undefined) {
            if (glyph_2 == "pb_scraft:glyph_accelerate") glyphCastTime = glyphCastTime - 0.3;
            if (glyph_2 == "pb_scraft:glyph_alleviate") glyphMana = glyphMana - 0.2;
            if (glyph_2 == "pb_scraft:glyph_intensify") this.glyphPower = this.glyphPower + 10;
        }

        const itemdata = config.CAST_ITEM_LIST.find((f) => f.identifier == itemUse.typeId);
        if (itemdata.element == spelldata.element) this.glyphPower += itemdata.spellPower;

        this.manacost = Math.floor(this.manacost * glyphMana);
        this.castTime = this.castTime * glyphCastTime;
    }

    cast() {
        this.player.playSound(this.soundCast, this.player.location);
    }

    stop() {
        this.isActive = false;
        lib.setCooldown(this.player, 0);
    }

    release() {
        this.trigger();
        this.isActive = false;
    }

    trigger() {
        lib.runCooldown(this.player);   //casting staff cooldown here
        const dimension = this.player.dimension;
        const view_vector = this.player.getViewDirection();
        const location = this.player.getHeadLocation();
        const impulse = this.projectileData.impulse;

        SPELL_PLAYERS.get(this.player.id).consumeMana(this.manacost);

        const projectile = mc.world.getDimension(dimension.id).spawnEntity(this.projectileData.identifier, { x: location.x + view_vector.x * 2, y: location.y + 0.75, z: location.z + view_vector.z * 2 });
        registerProjectile(projectile, this.projectileData);

        const component = projectile.getComponent("minecraft:projectile");
        component.owner = this.player;

        projectile.addEffect('slow_falling', 2 * mc.TicksPerSecond, { amplifier: 1, showParticles: false });
        component.shoot({ x: view_vector.x * impulse, y: view_vector.y * impulse, z: view_vector.z * impulse });
        dimension.playSound(this.projectileData.soundLaunch, location);
    }

    tick() {
        if (this.isActive) {
            lib.runCooldown(this.player);
            if (this.timeIndex % this.castTime == 0) this.cast();
            if (this.timeIndex >= this.castTime) this.isCharged = true;
            this.timeIndex++;
        }
    }
}

export function impact(data) {

    const dimension = data.dimension.id;
    const location = data.location;
    const projectile = data.projectile;
    const caster = data.source;
    const projectileData = config.EFFECT_LIST.find((f) => f.identifier == data.projectile.typeId);

    projectileData.particle_impact.forEach(element => { mc.world.getDimension(dimension).spawnParticle(element, location); });
    data.dimension.playSound(projectileData.soundImpact, location, { volume: 100.0 });
    deleteProjectile(projectile);

    let damage = projectileData.damage;
    if (caster != undefined) {

        //retrieve damage scaling from cast item
        const mainhand = caster.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand);
        const itemUse = mainhand.getItem();
        let glyphPower = 0;

        if (itemUse != undefined) {
            const spell = itemUse.getDynamicProperty("pb_scraft_spell");
            const glyph_1 = itemUse.getDynamicProperty("pb_scraft_glyph_1");
            const glyph_2 = itemUse.getDynamicProperty("pb_scraft_glyph_2");

            if (glyph_1 != undefined) {
                if (glyph_1 == "pb_scraft:glyph_intensify") glyphPower += 10;
            }

            if (glyph_2 != undefined) {
                if (glyph_2 == "pb_scraft:glyph_intensify") glyphPower += 10;
            }

            const spelldata = config.SPELL_LIST.find((f) => f.projectile == projectileData.identifier);
            const itemdata = config.CAST_ITEM_LIST.find((f) => f.identifier == itemUse.typeId);
            if (itemdata != undefined) {
                if (itemdata.element == spelldata.element) glyphPower += itemdata.spellPower
            }

            if (spell != spelldata.identifier) glyphPower = 0;
        }

        damage = damage + projectileData.spellpower * (SPELL_PLAYERS.get(caster.id).spellPower) + projectileData.spellpower * glyphPower;
        damage = damage * config.SCALING;
    }
    try {
        for (let entity of lib.targetMobMonster(location, dimension, projectileData.radius)) {
            entity.applyDamage(damage, { cause: mc.EntityDamageCause.contact, damagingEntity: caster });
            entity.applyKnockback(entity.location.x - location.x, entity.location.z - location.z, projectileData.knockback_horizontal, projectileData.knockback_vertical);
        }

        if (config.PVP.enabled) {
            const pvp_damage = damage * config.PVP.scaling;
            for (let entity of mc.world.getDimension(dimension).getEntities({ location: location, families: ["player"], maxDistance: projectileData.radius })) {
                if (entity != caster) {
                    entity.applyDamage(pvp_damage, { cause: mc.EntityDamageCause.contact, damagingEntity: caster });
                    entity.applyKnockback(entity.location.x - location.x, entity.location.z - location.z, projectileData.knockback_horizontal, projectileData.knockback_vertical);
                }
            }
        }
    }
    catch (error) { }
}
