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 SpellAura {

    player;
    spellPlayer;
    cooldown;
    name;
    manacost;
    castTime;
    soundCast;
    particlesCast;
    projectileData;
    totalTime = 10 * mc.TicksPerSecond;

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

    constructor(player, spellData, itemUse) {
        this.player = player;
        this.spellPlayer = SPELL_PLAYERS.get(player.id);
        this.itemUse = itemUse;

        this.name = spellData.identifier;
        this.manacost = spellData.manacost;;
        this.castTime = spellData.castTime;;
        this.cooldown = spellData.cooldown;
        this.soundCast = spellData.soundCast;
        this.particlesTarget = spellData.particlesTarget;
        this.particlesCast = spellData.particlesCast;

        this.projectileData = config.EFFECT_LIST.find((f) => f.identifier == spellData.projectile);
        this.spellData = spellData;

        for (let spell of SPELL_PLAYERS.get(player.id).tickingSpells.values()) {
            if (config.SPELL_LIST.find((f) => f.identifier == spell.name).type == "aura") {
                spell.stop();
            }
        }

        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() {

    }

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

        const dimension = this.player.dimension;
        const footlocation = this.player.location;

        if (this.spellData.particlesSetup != undefined) {
            this.spellData.particlesSetup.forEach(element => { mc.world.getDimension(dimension.id).spawnParticle(element, footlocation); });
        }
        dimension.playSound("pb_scraft.cast_loop_5", footlocation);
    }

    trigger() {
        const dimension = this.player.dimension;
        const location = this.player.getHeadLocation();
        const footlocation = this.player.location;

        if (this.particlesTarget != undefined) {
            let mvm = new mc.MolangVariableMap();
            mvm.setFloat(`variable.direction`, -Math.round(this.player.getRotation().y));
            mvm.setFloat(`variable.direction_y`, -this.player.getRotation().x * Math.PI / 180);

            this.particlesTarget.forEach(element => { mc.world.getDimension(dimension.id).spawnParticle(element, footlocation, mvm); });
        }

        let damage = this.projectileData.damage + this.projectileData.spellpower * this.spellPlayer.spellPower + this.projectileData.spellpower * this.glyphPower;;
        damage = damage * config.SCALING;
        
        if (this.timeIndex % this.spellData.damageTick == 0) {
            if(this.projectileData.target == "other")
            {
                try {
                    for (let entity of mc.world.getDimension(dimension.id).getEntities({ location: location, families: ["mob"], excludeFamilies: ["npc", "player", "projectile", "prop", "inanimate"], maxDistance: this.projectileData.radius })) {
                        entity.applyDamage(damage, { cause: mc.EntityDamageCause.contact, damagingEntity: this.player });
                        this.projectileData.particle_impact.forEach(element => { mc.world.getDimension(dimension.id).spawnParticle(element, entity.location); });
                        dimension.playSound(this.projectileData.soundImpact, entity.location);
                        entity.applyKnockback(entity.location.x - location.x, entity.location.z - location.z, this.projectileData.knockback_horizontal, this.projectileData.knockback_vertical);

                        if(this.projectileData.ignite != undefined) entity.setOnFire(this.projectileData.ignite);
                        if(this.projectileData.effect != undefined) entity.addEffect(this.projectileData.effect.type, this.projectileData.effect.duration, this.projectileData.effect.options);
                    }
                }
                catch (error) { }
            };
            if(this.projectileData.target == "self")
            {
                for (let entity of mc.world.getDimension(dimension.id).getEntities({ location: location, families: ["player"], excludeFamilies: ["projectile", "prop", "inanimate"], maxDistance: this.projectileData.radius })) {
                    dimension.playSound(this.projectileData.soundImpact, entity.location);
                    this.projectileData.particle_impact.forEach(element => { mc.world.getDimension(dimension.id).spawnParticle(element, entity.location); });

                    if(this.projectileData.effect != undefined) entity.addEffect(this.projectileData.effect.type, this.projectileData.effect.duration, this.projectileData.effect.options);
                }
            }
        }
    }

    tick() {
        if (this.isActive) {
            if (this.timeIndex % this.castTime == 0 && this.timeIndex < this.castTime) {
                lib.runCooldown(this.player);
                this.cast();
            }
            if (this.timeIndex == this.castTime) this.setup();
            if (this.timeIndex >= this.castTime) this.trigger();
            if (this.timeIndex > this.totalTime) this.isActive = false;
            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);

    deleteProjectile(projectile);
}
