import {system, world} from "@minecraft/server"
import {getScore} from "cubc/mo_en/armor"
import {hitboxes} from "cubc/mo_en/hitboxes"
import {getRandomInt} from "cubc/mo_en/tool"

function applyMutualExclusiveSwordEffect(damager, hurtEntity, particleHeight) {
    const availableEffects = [];
    const iceBoundScore = getScore(damager, "ice_bound");

    if (iceBoundScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand(`effect @e[family=mob, r=2.5] slowness 3 255`);
            hurtEntity.runCommand(`effect @s[type=player] slowness 5 5`);
            hurtEntity.runCommand(`execute positioned ~~${particleHeight / 2}~ run function cubc/mo_en/particle/ice_explosion_medium_1`);
        });
    }

    const venoScore = getScore(damager, "venom");
    if (venoScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand(`effect @s poison ${venoScore + 2} ${venoScore + 1}`);
            hurtEntity.runCommand(`effect @e[r=${venoScore + 1}, family=mob] poison ${venoScore + 2} ${venoScore + 1}`);
            hurtEntity.runCommand(`execute positioned ~~${particleHeight / 2}~ run function cubc/mo_en/particle/explosion5`);
        });
    }

    const blackMagicScore = getScore(damager, "black_magic");
    if (blackMagicScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand(`execute positioned ~~${particleHeight / 2}~ run function cubc/mo_en/particle/wither_explosion_medium_1`);
        });
    }

    const dadJokeScore = getScore(damager, "dad_joke");
    if (dadJokeScore > 0) {
        availableEffects.push(() => {
            system.runTimeout(() => {
                try {
                    hurtEntity.runCommand(`damage @s ${Math.ceil(10)} magic`);
                    damager.runCommand(`function cubc/mo_en/apply_enchants/sword/random_quote`);
                } catch {
                }
            }, 14);
        });
    }

    let effectIndex = 0;
    if (availableEffects.length > 0) {
        effectIndex = getRandomInt(0, availableEffects.length - 1);
        const randomEffect = availableEffects[effectIndex];
        randomEffect();
    }

    return effectIndex;
}


function applyMutualExclusiveBowEffectBlock(damager, location) {
    const availableEffects = [];
    let {x: x, y: y, z: z} = location;

    const lightnin = getScore(damager, "lightning");
    if (lightnin > 0) {
        availableEffects.push(() => {
            damager.runCommand(`summon lightning_bolt ${x} ${y} ${z}`);
            damager.runCommand(`execute positioned ${x} ${y} ${z} run function cubc/mo_en/particle/explosion2`);
        });
    }

    const cometRainScore = getScore(damager, "fireball_rain");
    let cometCount = damager.dimension.getEntities({
        type: "cubc_mo_en:comet",
        location: location,
        maxDistance: 90
    }).length;
    if (cometRainScore > 0 && cometCount <= 0) {
        availableEffects.push(() => {
            startFireRain(damager.dimension, location, cometRainScore);
        });
    }

    const explosnScore = getScore(damager, "explosion");
    if (explosnScore > 0) {
        availableEffects.push(() => {
            damager.runCommand(`summon cubc_mo_en:instant_explode_${explosnScore} ${x} ${y} ${z}`);
        });
    }

    if (availableEffects.length > 0) {
        const randomEffect = availableEffects[getRandomInt(0, availableEffects.length - 1)];
        randomEffect();
    }
}

function applyMutualExclusiveBowEffect(damager, hurtEntity, particleHeight) {
    const availableEffects = [];

    const lightnin = getScore(damager, "lightning");
    if (lightnin > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand(`summon lightning_bolt`);
            hurtEntity.runCommand(`execute positioned ~~${particleHeight / 2}~ run function cubc/mo_en/particle/explosion2`);
        });
    }

    const fireTrailScore = getScore(damager, "fire_trail");
    if (fireTrailScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand("function cubc/mo_en/fire_trail/hit");
        });
    }

    const cometRainScore = getScore(damager, "fireball_rain");
    let cometCount = hurtEntity.dimension.getEntities({
        type: "cubc_mo_en:comet",
        location: hurtEntity.location,
        maxDistance: 90
    }).length;
    if (cometRainScore > 0 && cometCount <= 0) {
        availableEffects.push(() => {
            startFireRain(hurtEntity.dimension, hurtEntity.location, cometRainScore);
        });
    }

    const fireBenderScore = getScore(damager, "fire_bender");
    if (fireBenderScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand('function cubc/mo_en/particle/fire_explosion_medium_1');
            let nearby_mobs = hurtEntity.dimension.getEntities({
                families: ["mob"],
                location: hurtEntity.location,
                maxDistance: 8
            });
            nearby_mobs.forEach((mob) => {
                mob.setOnFire(5, true)
            });
        });
    }

    const explosnScore = getScore(damager, "explosion");
    if (explosnScore > 0) {
        availableEffects.push(() => {
            hurtEntity.runCommand(`summon cubc_mo_en:instant_explode_${explosnScore}`);
        });
    }

    if (availableEffects.length > 0) {
        const randomEffect = availableEffects[getRandomInt(0, availableEffects.length - 1)];
        randomEffect();
    }

    applyMutualExclusiveBowEffectBlock(damager, hurtEntity.location);
}


function applyAdditionalEffects(damager, hurtEntity, effectIndex) {

    // Sword effects
    if (effectIndex !== 4) {
        const doubleHit = getScore(damager, "double_hit");
        if (doubleHit > 0) {
            system.runTimeout(() => {
                try {
                    hurtEntity.runCommand(`damage @s ${Math.ceil(doubleHit * 2)} magic`);
                } catch {
                }
            }, 14);
        }
    }
    const witheScore = getScore(damager, "wither");
    if (witheScore > 0) {
        hurtEntity.runCommand(`effect @s wither ${3 + Math.ceil(witheScore / 2)} ${witheScore}`);
    }

    // Rage score
    const ragScore = getScore(damager, "rage");
    if (ragScore > 0) {
        hurtEntity.runCommand(`particle cubc_mo_en:hit`);
    }

    // Bow / Weapon effects
    const ravenouScore = getScore(damager, "ravenous");
    if (ravenouScore > 0) {
        damager.runCommand(`effect @s saturation 1 ${ravenouScore * 3}`);
        hurtEntity.runCommand(`effect @s hunger 2 ${ravenouScore * 30} true`);
    }

    const lifesteaScore = getScore(damager, "lifesteal");
    if (lifesteaScore > 0) {
        damager.runCommand(`effect @s regeneration 1 ${lifesteaScore * 3}`);
    }

    const damageScore = getScore(damager, "damager");
    if (damageScore > 0) {
        hurtEntity.runCommand(`damage @s ${Math.ceil(damageScore * 1.5)} magic`);
    }
    // Bow effects
    const heavyShotScore = getScore(damager, "heavy_shot");
    if (heavyShotScore > 0) {
        hurtEntity.runCommand(`damage @s ${Math.ceil(heavyShotScore * 2)} magic`);
    }

    const blindScore = getScore(damager, "blindness");
    if (blindScore > 0) {
        hurtEntity.runCommand(`effect @s blindness 3 255`);
        hurtEntity.runCommand(`effect @s[family=mob] slowness 3 255`);
    }
}

world.afterEvents.entityHurt.subscribe((event) => {

    let damagingEntity = event.damageSource.damagingEntity;
    if (damagingEntity === undefined) return;

    try {
        if (damagingEntity.typeId !== "minecraft:player") {
            return;
        }


        let hurtEntity = event.hurtEntity;
        let particleHeight = getHeight(hurtEntity) / 2;

        // Apply mutual exclusive effects
        let effectIndex = 0;
        if (event.damageSource.cause === "entityAttack") {
            effectIndex = applyMutualExclusiveSwordEffect(damagingEntity, hurtEntity, particleHeight);
        }

        // Apply additional effects
        applyAdditionalEffects(damagingEntity, hurtEntity, effectIndex);
    } catch (e) {
    }
});

world.afterEvents.entityDie.subscribe((event) => {
    let damagingEntity = event.damageSource.damagingEntity;
    if (damagingEntity === undefined) return;

    try {
        if (damagingEntity.typeId === "minecraft:player") {
            let deadEntity = event.deadEntity;
            let {x: x, y: y, z: z} = deadEntity.location;

            // XP boost
            const xpBoostScore = getScore(damagingEntity, "xp_boost");
            for (let i = 0; i < xpBoostScore; i++) {
                system.runTimeout(() => {
                    damagingEntity.runCommand(`summon xp_orb ${x} ${y} ${z}`);
                }, 5);
            }

            // Extra loot
            const lootSurgeScore = getScore(damagingEntity, "loot_surge");
            if (lootSurgeScore > 0 && Math.random() < (0.15 + 0.15 * lootSurgeScore)) {
                let typeId = deadEntity.typeId.replace("minecraft:", "");
                event.deadEntity.runCommand(`loot spawn ${x} ${y} ${z} loot "entities/${typeId}"`);
            }
        }
    } catch (e) {
    }
});

function getHeight(entity) {
    try {
        return hitboxes[entity.typeId]["height"];
    } catch (e) {
        return 1;
    }
}

function startFireRain(dimension, location, intensity) {
    const {x: x, y: y, z: z} = location;
    const r = intensity * 3;

    for (let i = 0; i < intensity * 3; i++) {
        let random_dx = Math.random() * r - r / 2;
        let random_dz = Math.random() * r - r / 2;
        let random_dy = Math.random() * r - r / 2 + 30;

        system.runTimeout(() => {
            dimension.runCommand(`execute as @r at @s positioned ${x} ${y} ${z} run summon cubc_mo_en:comet ~${random_dx} ~${random_dy} ~${random_dz}`);
        }, 6 * i);
    }
}

world.afterEvents.projectileHitBlock.subscribe((eventData) => {
    try {
        if (!eventData.getBlockHit().block.permutation.matches('minecraft:water')) {
            eventData.projectile.runCommand("tag @s remove cubc_mo_en_fire_trail");
            if (eventData.projectile.getTags().includes("extra") || !eventData.source) {
                return;
            }
            if (eventData.source.typeId === "minecraft:player" && eventData.projectile.typeId === "minecraft:arrow") {
                applyMutualExclusiveBowEffectBlock(eventData.source, eventData.getBlockHit().block.location);
                eventData.projectile.runCommand("tag @s add cubc_mo_en_extra");
            }
        }
    } catch (e) {
    }
});

world.afterEvents.projectileHitEntity.subscribe((eventData) => {
    if (!eventData.source) return;
    if (eventData.source.typeId === "minecraft:player" && eventData.getEntityHit().entity.typeId !== "cubc_mo_en:projectile_target") {
        const fireTrailScore = getScore(eventData.source, "fire_trail");
        if (fireTrailScore > 0) {
            eventData.getEntityHit().entity.runCommand("scoreboard players set @s cubc_mo_en_set_on_fire 10");
        }
        if (eventData.projectile.typeId === "minecraft:arrow") {
            const hurtEntity = eventData.getEntityHit().entity
            let particleHeight = getHeight(hurtEntity) / 2;
            applyMutualExclusiveBowEffect(eventData.source, hurtEntity, particleHeight);
        }
    }
});
