import {
    EffectTypes,
    EntityComponentTypes,
    EntityDamageCause,
    ItemCompleteUseEvent,
    ItemStack,
    MolangVariableMap,
    Player,
    system,
    world,
} from "@minecraft/server";
import { Bosses } from "../bosses/BossHealthHandler";
import {
    ColorPalette,
    getOwner,
    handlePlayerFly,
    isTamed,
    knockbackEntity,
    spawnConeEntities,
} from "../utils/utils";

var TargetType;

(function (TargetType) {
    TargetType["SELF"] = "self";

    TargetType["OTHER"] = "other";
})(TargetType || (TargetType = {}));

const DEFAULT_COLOR = { red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0 };

/**
 * @typedef {Object} Particle
 * @property {string} name - Identifier of the particle.
 * @property {boolean} changesColor - Whether the particle changes color.
 * @property {string} color - Color of the particle (hex code or palette constant).
 *
 * @typedef {Object} KnockbackOptions
 * @property {number} horizontalStrength - Strength of horizontal knockback.
 * @property {number} verticalStrength - Strength of vertical knockback.
 *
 * @typedef {Object} OnHitOptions
 * @property {boolean} applyKnockback - Whether to apply knockback on hit.
 * @property {KnockbackOptions} knockbackOptions - Configuration for knockback strength.
 * @property {boolean} causes_fire - Whether the hit causes fire damage.
 * @property {string[]} sounds - Sounds that plays on hit.
 * @property {Array} effects - List of status effects applied on hit.
 * @property {Particle[]} particles - Particles emitted on impact.
 *
 * @typedef {Object} SkillProp
 * @property {string} name - Name of the cooldown or skill identifier.
 * @property {number} cooldown - Cooldown time in seconds.
 *
 * @typedef {Object} OnUseAction
 * @property {Function} exec - Function to execute when the action is triggered.
 * @property {SkillProp} prop - Properties of the skill (name and cooldown).
 *
 * @typedef {Object} OnUseActions
 * @property {OnUseAction} [sneaking] - Action executed while sneaking.
 * @property {OnUseAction} [stand] - Action executed while standing.
 *
 * @typedef {Object} WeaponInfo
 * @property {Array} passive_effects - List of passive effects applied to the weapon.
 * @property {OnUseActions} on_use - Actions triggered when using the weapon.
 * @property {OnHitOptions} on_hit - Properties and particle effects when hitting.
 */

/**
 * Map containing custom weapon definitions and their behaviors.
 * @type {Map<string, WeaponInfo>}
 */
const WeaponInfos = new Map([
    [
        "shadow_scythe",
        {
            passive_effects: [],
            on_use: {
                sneaking: {
                    exec: () => {},
                    prop: {
                        name: "ninja_cd:none",
                        cooldown: 0,
                    },
                },
                stand: {
                    exec: occultMagic,
                    prop: {
                        name: "ninja_cd:shadow_vortex_skill",
                        cooldown: 15,
                    },
                },
            },
            on_hit: {
                applyKnockback: false,
                knockbackOptions: { horizontalStrength: 1.0, verticalStrength: 0.4 },
                causes_fire: false,
                sounds: [""],
                effects: [
                    {
                        applyEffectChance: 100,
                        target: TargetType.OTHER,
                        name: "minecraft:wither",
                        duration: 10,
                        options: { amplifier: 1, showParticles: true },
                    },
                ],
                particles: [
                    {
                        name: "pixell_bbo:shadow_clawn",
                        changesColor: false,
                        color: ColorPalette.indigoLight,
                    },
                ],
            },
        },
    ],
    [
        "burazazu_sword",
        {
            passive_effects: [],
            on_use: {
                sneaking: {
                    exec: () => {},
                    prop: {
                        name: "ninja_cd:none",
                        cooldown: 0,
                    },
                },
                stand: {
                    exec: bladeFury,
                    prop: {
                        name: "ninja_cd:blade_fury_skill",
                        cooldown: 10,
                    },
                },
            },
            on_hit: {
                applyKnockback: false,
                knockbackOptions: { horizontalStrength: 1.0, verticalStrength: 0.4 },
                causes_fire: false,
                sounds: ["ambient.weather.lightning.impact", "ambient.weather.thunder"],
                effects: [],
                particles: [
                    {
                        name: "pixell_bbo:thunderbolt_hit",
                        changesColor: false,
                        color: ColorPalette.indigoLight,
                    },
                ],
            },
        },
    ],
    [
        "craterus_fangs",
        {
            passive_effects: [],
            on_use: {
                sneaking: {
                    exec: () => {},
                    prop: {
                        name: "ninja_cd:none",
                        cooldown: 0,
                    },
                },
                stand: {
                    exec: toxicRoar,
                    prop: {
                        name: "ninja_cd:toxic_roar_skill",
                        cooldown: 20,
                    },
                },
            },
            on_hit: {
                applyKnockback: false,
                knockbackOptions: { horizontalStrength: 1.0, verticalStrength: 0.4 },
                causes_fire: false,
                sounds: [""],
                effects: [
                    {
                        applyEffectChance: 100,
                        target: TargetType.OTHER,
                        name: "minecraft:fatal_poison",
                        duration: 10,
                        options: { amplifier: 1, showParticles: true },
                    },
                ],
                particles: [
                    {
                        name: "pixell_bbo:craterus_toxic_smoke_p",
                        changesColor: false,
                        color: ColorPalette.indigoLight,
                    },
                ],
            },
        },
    ],
    [
        "ares_sword",
        {
            passive_effects: [],
            on_use: {
                sneaking: {
                    exec: () => {},
                    prop: {
                        name: "ninja_cd:none",
                        cooldown: 0,
                    },
                },
                stand: {
                    exec: aresExplosion,
                    prop: {
                        name: "ninja_cd:fire_explosion_skill",
                        cooldown: 15,
                    },
                },
            },
            on_hit: {
                applyKnockback: false,
                knockbackOptions: { horizontalStrength: 1.0, verticalStrength: 0.4 },
                causes_fire: true,
                sounds: [""],
                effects: [
                    /*  {
                        applyEffectChance: 100,
                        target: TargetType.OTHER,
                        name: "minecraft:fatal_poison",
                        duration: 10,
                        options: { amplifier: 1, showParticles: true },
                    }, */
                ],
                particles: [
                    {
                        name: "pixell_bbo:fire",
                        changesColor: false,
                        color: ColorPalette.indigoLight,
                    },
                ],
            },
        },
    ],
    [
        "hades_staff",
        {
            passive_effects: [],
            on_use: {
                sneaking: {
                    exec: () => {},
                    prop: {
                        name: "ninja_cd:none",
                        cooldown: 0,
                    },
                },
                stand: {
                    exec: underworldSpheres,
                    prop: {
                        name: "ninja_cd:underworld_spheres_skill",
                        cooldown: 20,
                    },
                },
            },
            on_hit: {
                applyKnockback: false,
                knockbackOptions: { horizontalStrength: 1.0, verticalStrength: 0.4 },
                causes_fire: true,
                sounds: [""],
                effects: [
                    /*  {
                        applyEffectChance: 100,
                        target: TargetType.OTHER,
                        name: "minecraft:fatal_poison",
                        duration: 10,
                        options: { amplifier: 1, showParticles: true },
                    }, */
                ],
                particles: [
                    /*  {
                        name: "pixell_bbo:fire",
                        changesColor: false,
                        color: ColorPalette.indigoLight,
                    }, */
                ],
            },
        },
    ],
]);

world.beforeEvents.worldInitialize.subscribe((event) => {
    const { itemComponentRegistry } = event;

    itemComponentRegistry.registerCustomComponent("self:weapon_skill", {
        onUse: (iEvent) => {
            const { itemStack, source } = iEvent;

            if (!itemStack) return;

            const fullName = itemStack.typeId.split(":")[1];

            const weapon = fullName;

            const weaponData = WeaponInfos.get(weapon);

            if (!weaponData) return;

            const { on_use } = weaponData;

            if (!source.isSneaking) {
                on_use.stand.exec(iEvent);
                return;
            }

            return;
        },
        onHitEntity(iEvent) {
            const { hitEntity, attackingEntity, itemStack, hadEffect } = iEvent;

            if (!itemStack || !hitEntity || !attackingEntity) return;

            const fullName = itemStack.typeId.split(":")[1];

            const weapon = fullName;

            const weaponData = WeaponInfos.get(weapon);

            if (!weaponData) return;

            const { on_hit } = weaponData;

            const { effects, particles, applyKnockback, knockbackOptions, causes_fire, sounds } =
                on_hit;

            if (particles && particles.length > 0) {
                for (let particle of particles) {
                    const { changesColor, name, color } = particle;

                    const lookDir = attackingEntity.getViewDirection();

                    const offset = {
                        x: 1,
                        y: 1,
                        z: 1,
                    };

                    const particleLocation = {
                        x: hitEntity.location.x - lookDir.x * offset.x,
                        y: hitEntity.location.y + 1.5 + lookDir.y * offset.y,
                        z: hitEntity.location.z - lookDir.z * offset.z,
                    };

                    if (changesColor) {
                        const particleMolang = new MolangVariableMap();

                        particleMolang.setColorRGBA("variable.color", color);

                        hitEntity.dimension.spawnParticle(name, particleLocation, particleMolang);

                        continue;
                    }

                    hitEntity.dimension.spawnParticle(name, particleLocation);
                }
            }

            if (causes_fire) {
                const isBoss = Bosses.has(hitEntity.typeId);

                if (!isBoss) {
                    hitEntity.setOnFire(5);
                }
            }

            if (sounds.length > 0) {
                for (let sound of sounds) {
                    attackingEntity.dimension.playSound(sound, attackingEntity.location, {
                        volume: 0.8,
                    });
                }
            }

            for (let effect of effects) {
                const { name, duration, applyEffectChance, options, target } = effect;

                const isValidEffect = EffectTypes.get(name);

                if (!isValidEffect) {
                    console.warn(`§eEffect: ${name} is not a valid effect!`);

                    continue;
                }

                const random = Math.round(Math.random() * 100);

                const chance = applyEffectChance;

                if (random <= chance) {
                    if (target == TargetType.OTHER) {
                        const hasEffect = hitEntity
                            .getEffects()
                            .some((e) => name.includes(e.typeId));

                        if (hasEffect) continue;

                        hitEntity.addEffect(name, duration * 20, {
                            amplifier: options.amplifier,
                            showParticles: options.showParticles,
                        });
                    }

                    if (target == TargetType.SELF) {
                        const hasEffect = attackingEntity
                            .getEffects()
                            .some((e) => name.includes(e.typeId));

                        if (hasEffect) continue;

                        attackingEntity.addEffect(name, duration * 20, {
                            amplifier: options.amplifier,
                            showParticles: options.showParticles,
                        });
                    }
                }
            }

            if (applyKnockback) {
                const { horizontalStrength, verticalStrength } = knockbackOptions;

                knockbackEntity(attackingEntity, hitEntity, horizontalStrength, verticalStrength);
            }
        },
    });
});

const runLoop = true;

const MAIN_LOOP = system.runInterval(() => {
    const players = world.getAllPlayers();

    for (let player of players) {
        if (runLoop) {
            //HANDLE PLAYER FLY
            handlePlayerFly(player, "gabriel_wings", { single_part: true });

            if (system.currentTick % (20 * 1) === 0) {
                handleItemCooldown(player, WeaponInfos);
            }
        }
    }
});

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function occultMagic(iEvent) {
    const { source, itemStack } = iEvent;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    startSkillCooldown(source, getWeapon(itemStack));

    const skillInfo = {
        damage: 4,
        duration: 8,
        radius: 8,
    };

    const impulseOptions = {
        horizontalStrength: 1,
        verticalStrength: 0.4,
    };

    const skillLocation = source.location;

    const magicCircleMolang = new MolangVariableMap();

    magicCircleMolang.setFloat("variable.duration", skillInfo.duration);

    source.dimension.spawnParticle(
        "pixell_bbo:magic_circle",
        {
            x: skillLocation.x,
            y: skillLocation.y + 0.15,
            z: skillLocation.z,
        },
        magicCircleMolang
    );

    const darkSpinMolang = new MolangVariableMap();

    darkSpinMolang.setFloat("variable.duration", 8);

    darkSpinMolang.setFloat("variable.psize", 3);

    source.dimension.spawnParticle(
        "pixell_bbo:dark_spin",
        {
            x: skillLocation.x,
            y: skillLocation.y,
            z: skillLocation.z,
        },
        darkSpinMolang
    );

    source.playSound("pixell_bbo.unknow_occult_magic", {
        volume: 1.0,
    });

    let duration = skillInfo.duration * 20;

    const runId = system.runInterval(() => {
        duration--;

        if (duration <= 0) {
            system.clearRun(runId);
            return;
        }

        if ((system.currentTick % 20) * 1 === 0) {
            const nearbyEntities = source.dimension.getEntities({
                location: skillLocation,
                maxDistance: skillInfo.radius,
                excludeTypes: [source.typeId, "pixell_bbo:deepslate_pot"],
            });

            for (let entity of nearbyEntities) {
                const isEntityTamed = isTamed(entity);

                if (!isEntityTamed) {
                    entity.applyDamage(skillInfo.damage, {
                        cause: EntityDamageCause.magic,
                        damagingEntity: source,
                    });

                    continue;
                }

                const owner = getOwner(entity);

                if (!owner) continue;

                if (owner.id != source.id) {
                    entity.applyDamage(skillInfo.damage, {
                        cause: EntityDamageCause.magic,
                        damagingEntity: source,
                    });
                }
            }
        }

        const nearbyEntities = source.dimension.getEntities({
            location: skillLocation,
            maxDistance: skillInfo.radius,
            excludeTypes: [source.typeId],
            excludeFamilies: ["boss", "portal"],
        });

        for (let entity of nearbyEntities) {
            const isEntityTamed = isTamed(entity);

            if (!isEntityTamed) {
                entity.applyImpulse({
                    x:
                        entity.location.x < skillLocation.x
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                    y:
                        entity.location.y < skillLocation.y
                            ? impulseOptions.verticalStrength
                            : -impulseOptions.verticalStrength,
                    z:
                        entity.location.z < skillLocation.z
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                });

                continue;
            }

            const owner = getOwner(entity);

            if (!owner) continue;

            if (owner.id != source.id) {
                entity.applyImpulse({
                    x:
                        entity.location.x < skillLocation.x
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                    y:
                        entity.location.y < skillLocation.y
                            ? impulseOptions.verticalStrength
                            : -impulseOptions.verticalStrength,
                    z:
                        entity.location.z < skillLocation.z
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                });
            }
        }
    });
}

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function shadowVortex(iEvent) {
    const { source, itemStack } = iEvent;

    const location = source.location;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    const darkSpinMolang = new MolangVariableMap();
    darkSpinMolang.setFloat("variable.duration", 12);

    source.dimension.spawnParticle("pixell_bbo:dark_spin", location, darkSpinMolang);

    const skillInfo = {
        damage: 4,
        duration: 8,
        radius: 8,
    };

    const impulseOptions = {
        horizontalStrength: 1,
        verticalStrength: 0.4,
    };

    let duration = skillInfo.duration * 20;

    const runId = system.runInterval(() => {
        duration--;

        if (duration <= 0) {
            system.clearRun(runId);
            return;
        }

        const nearbyEntities = source.dimension.getEntities({
            location: location,
            maxDistance: skillInfo.radius,
            excludeTypes: [source.typeId],
        });

        for (let entity of nearbyEntities) {
            const isEntityTamed = isTamed(entity);

            if (!isEntityTamed) {
                entity.applyImpulse({
                    x:
                        entity.location.x < location.x
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                    y:
                        entity.location.y < location.y
                            ? impulseOptions.verticalStrength
                            : -impulseOptions.verticalStrength,
                    z:
                        entity.location.z < location.z
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                });

                continue;
            }

            const owner = getOwner(entity);

            if (!owner) continue;

            if (owner.id != source.id) {
                entity.applyImpulse({
                    x:
                        entity.location.x < location.x
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                    y:
                        entity.location.y < location.y
                            ? impulseOptions.verticalStrength
                            : -impulseOptions.verticalStrength,
                    z:
                        entity.location.z < location.z
                            ? impulseOptions.horizontalStrength
                            : -impulseOptions.horizontalStrength,
                });
            }
        }
    });

    startSkillCooldown(source, getWeapon(itemStack));
}

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function toxicRoar(iEvent) {
    const { source, itemStack } = iEvent;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    startSkillCooldown(source, getWeapon(itemStack));

    const location = source.location;

    const direction = source.getViewDirection();

    source.playSound("pixell_bbo.craterus.roar_single", {
        volume: 1.0,
    });

    const toxicRoarMolang = new MolangVariableMap();

    toxicRoarMolang.setVector3("variable.direction", {
        x: direction.x,
        y: direction.y,
        z: direction.z,
    });

    toxicRoarMolang.setFloat("variable.duration", 12);

    source.dimension.spawnParticle(
        "pixell_bbo:roar_skill",
        {
            x: location.x,
            y: location.y + 1.0,
            z: location.z,
        },
        toxicRoarMolang
    );

    const poisonDistance = 8;
    const poisonRadius = 6;

    const blockLoc = source.getBlockFromViewDirection({
        includePassableBlocks: true,
        includeLiquidBlocks: true,
        maxDistance: 16,
    })?.block?.location;

    const entityLoc = source.getEntitiesFromViewDirection({
        maxDistance: 16,
    })[0]?.entity?.location;

    if (!blockLoc && !entityLoc) return;

    source.dimension.spawnParticle("pixell_bbo:craterus2_poison", blockLoc ?? entityLoc);

    const entities = source.dimension.getEntities({
        location: blockLoc ?? entityLoc,
        maxDistance: poisonRadius,
        excludeTypes: [source.typeId],
    });

    for (let entity of entities) {
        entity.addEffect("fatal_poison", 10 * 20);
    }
}

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function aresExplosion(iEvent) {
    const { source, itemStack } = iEvent;

    const skillDelay = 1.2 * 20;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    startSkillCooldown(source, getWeapon(itemStack));

    source.playSound("pixell_bbo.ares_berserk_transform", {
        volume: 1.0,
    });

    system
        .waitTicks(skillDelay)
        .then(() => {
            const location = source.location;

            const direction = source.getViewDirection();

            source.dimension.spawnParticle("pixell_bbo:flame_explosion", {
                x: location.x,
                y: location.y + 0.8,
                z: location.z,
            });

            const entities = source.dimension.getEntities({
                location: source.location,
                maxDistance: 8,
                excludeTypes: [source.typeId, "pixell_bbo:skybox"],
            });

            for (let entity of entities) {
                entity?.setOnFire(5);

                entity.applyDamage(6, {
                    cause: EntityDamageCause.fire,
                    damagingEntity: source,
                });
            }
        })
        .catch((e) => {
            console.error("Error " + e);
        });
}

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function bladeFury(iEvent) {
    const { source, itemStack } = iEvent;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    const location = source.location;

    const direction = source.getViewDirection();

    const entities = source.dimension.getEntities({
        location: source.location,
        maxDistance: 8,
        excludeTypes: [
            source.typeId,
            "minecraft:exp_orb",
            "minecraft:item",
            "pixell_bbo:portal",
            "pixell_bbo:skybox",
            "pixell_bbo:deepslate_pot",
        ],
    });

    const liveEntities = entities.filter((e) => {
        const healthComponent = e.getComponent(EntityComponentTypes.Health);

        if (!healthComponent) return false;
        return true;
    });

    if (entities.length == 0 || liveEntities.length == 0) {
        source.onScreenDisplay.setActionBar("§lNo enemies in range!");
        return;
    }

    source.playSound("ambient.weather.lightning.impact", {
        volume: 0.8,
    });
    source.playSound("ambient.weather.thunder", {
        volume: 0.8,
    });

    for (let e = 0; e < entities.length; e++) {
        const entity = entities[e];

        const healthComponent = entity.getComponent(EntityComponentTypes.Health);

        if (!healthComponent) continue;

        system.runTimeout(() => {
            const trailMolang = new MolangVariableMap();

            trailMolang.setVector3("variable.direction", {
                x: source.location.x < entity.location.x ? 1 : -1,
                y: 0,
                z: source.location.z < entity.location.z ? 1 : -1,
            });

            trailMolang.setVector3("variable.accel", {
                x: source.location.x < entity.location.x ? -10 : 10,
                y: 0,
                z: source.location.z < entity.location.z ? -10 : 10,
            });

            source.dimension.spawnParticle(
                "pixell_bbo:thunder_trail",
                source.location,
                trailMolang
            );

            source.tryTeleport(
                {
                    x: entity.location.x,
                    y: entity.location.y + 1,
                    z: entity.location.z,
                },
                { checkForBlocks: false }
            );

            source.addEffect("invisibility", 1 * 20, { amplifier: 0, showParticles: false });

            entity.dimension.spawnParticle("pixell_bbo:thunder_explode", entity.location);

            source.playSound("ambient.weather.lightning.impact", {
                volume: 0.5,
            });
            source.playSound("ambient.weather.thunder", {
                volume: 0.5,
            });

            source.playSound("pixell_bbo.ares_attack_1", {
                pitch: 1.2,
            });

            entity.applyDamage(6);
        }, e * 0.2 * 20);
    }

    startSkillCooldown(source, getWeapon(itemStack));
}

/**
 *
 * @param {ItemCompleteUseEvent} iEvent
 */
function underworldSpheres(iEvent) {
    const { source, itemStack } = iEvent;

    const skillDelay = 2 * 20;

    const inCooldown = isInCooldown(source, itemStack);

    if (inCooldown) return;

    startSkillCooldown(source, getWeapon(itemStack));

    const location = source.location;

    const direction = source.getViewDirection();

    source.playSound("pixell_bbo.hades_form_fire_orb");

    source.dimension.spawnParticle("pixell_bbo:aura_spark", source.location);
    source.dimension.spawnParticle("pixell_bbo:spiral_hades", source.location);

    system
        .waitTicks(skillDelay)
        .then(() => {
            const projectiles = spawnConeEntities(source, "pixell_bbo:underworld_sphere", 6, 90, 3);

            const defaultDir = source.getViewDirection();

            const power = 2.0;
            const gravity = 0.01;
            const sound = "";

            let degrees = -67.5;

            for (let i = 1; i <= projectiles.length; i++) {
                const projectile = projectiles[i - 1];

                const rotation = projectile.getRotation();

                projectile.setRotation({ x: rotation.x, y: rotation.y + degrees });

                const pDirection = projectile.getViewDirection();

                const projComp = projectile.getComponent("minecraft:projectile");

                projComp.owner = source;

                projComp.gravity = gravity;

                const dir = projectile.getViewDirection();

                projComp.shoot({
                    x: pDirection.x * power,
                    y: defaultDir.y * power,
                    z: pDirection.z * power,
                });

                degrees += 22.5;
            }
        })
        .catch((e) => console.error("Error " + e));
}

/**
 *
 * @param {Player} player
 * @param {Map<string, WeaponInfo>} items
 */
function handleItemCooldown(player, items) {
    for (let [k, v] of Array.from(items)) {
        const cooldownProps = [v.on_use.sneaking.prop, v.on_use.stand.prop];

        for (let prop of cooldownProps) {
            const { name, cooldown } = prop;
            /**
             * @type {number | undefined}
             */
            const playerItemCooldown = player.getDynamicProperty(name);

            //console.warn(`${name}: ${playerItemCooldown}`);

            if (playerItemCooldown == undefined) {
                player.setDynamicProperty(name, cooldown);
                continue;
            }

            if (playerItemCooldown > 0) {
                player.setDynamicProperty(name, playerItemCooldown - 1);
            }
        }
    }
}

/**
 *
 * @param {Player} player
 * @param {string} weapon
 * @returns
 */
function startSkillCooldown(player, weapon) {
    const weaponData = WeaponInfos.get(weapon);

    if (!weaponData) return;

    const { on_use } = weaponData;
    const { sneaking, stand } = on_use;

    if (player.isSneaking) {
        player.setDynamicProperty(sneaking.prop.name, sneaking.prop.cooldown);
        return;
    }

    player.setDynamicProperty(stand.prop.name, stand.prop.cooldown);
}

/**
 *
 * @param {Player} player
 * @param {ItemStack} itemStack
 */
function getWeapon(itemStack) {
    if (!itemStack) return;

    const fullName = itemStack.typeId.split(":")[1];

    const weapon = fullName;

    const weaponData = WeaponInfos.get(weapon);

    if (!weaponData) return;

    return weapon;
}

/**
 *
 * @param {Player} player
 * @param {ItemStack} itemStack
 */
function isInCooldown(player, itemStack) {
    if (!itemStack) return;

    const weapon = WeaponInfos.get(getWeapon(itemStack));

    if (!weapon) return;

    const { on_use } = weapon;

    if (player.isSneaking) {
        player.onScreenDisplay.setActionBar(
            `§b[Cooldown: ${player.getDynamicProperty(on_use.sneaking.prop.name)}s]`
        );

        return player.getDynamicProperty(on_use.sneaking.prop.name) > 0 ?? true;
    }

    player.onScreenDisplay.setActionBar(
        `§b[Cooldown: ${player.getDynamicProperty(on_use.stand.prop.name)}s]`
    );

    return player.getDynamicProperty(on_use.stand.prop.name) > 0 ?? true;
}
