import { EquipmentSlot, system, world, Player, Block } from "@minecraft/server";
import { getRandomBetween, handleItemDurability, shootProjectile } from "../utils/utils";

const WeaponSkills = new Map([
    [
        "ns_ma:desert_dagger",
        {
            exec: applyInvisibility,
        },
    ],
    [
        "ns_ma:magical_staff",
        {
            exec: staffShoot,
        },
    ],
    [
        "ns_ma:monster_king_sword",
        {
            exec: summonMinions,
        },
    ],
]);

world.afterEvents.itemUse.subscribe((event) => {
    const { itemStack: item, source: player } = event;

    if (item) {
        const cooldown = item.getComponent("minecraft:cooldown");

        if (cooldown) {
            const cooldownTicks = cooldown?.cooldownTicks;
            const remainingCooldown = cooldown?.getCooldownTicksRemaining(player);

            if (remainingCooldown == 0) {
                cooldown.startCooldown(player);

                WeaponSkills.get(item.typeId)?.exec(player);
            }
        }
    }
});

world.afterEvents.playerBreakBlock.subscribe((event) => {
    const { itemStackBeforeBreak, block, brokenBlockPermutation } = event;
});

world.beforeEvents.playerBreakBlock.subscribe((event) => {
    const { itemStack, block } = event;

    /* console.warn(block.getTags().toString());
    console.warn(block.typeId);
 */
    if (itemStack) {
        if (itemStack.typeId == "ns_ma:forest_axe") {
            if (isLog(block)) {
                capitate(block);
            }
        }
    }
});

world.beforeEvents.worldInitialize.subscribe((event) => {
    const onMine = event.itemComponentRegistry.registerCustomComponent("item:on_mine", {
        onMineBlock: (iEvent) => {
            const { source: player, itemStack } = iEvent;

            handleItemDurability(player, itemStack);
        },
    });

    const igniteEnemy = event.itemComponentRegistry.registerCustomComponent("item:ignite", {
        onHitEntity: (iEvent) => {
            const { attackingEntity, hitEntity, hadEffect, itemStack } = iEvent;

            if (hitEntity) {
                hitEntity.setOnFire(10);
            }
        },
    });

    const riptide = event.itemComponentRegistry.registerCustomComponent("item:riptide", {
        onUse: (iEvent) => {
            const { itemStack, source } = iEvent;

            if (source instanceof Player) {
                const direction = source.getViewDirection();
                const rotation = source.getRotation();

                const cooldown = itemStack.getComponent("minecraft:cooldown");

                if (cooldown) {
                    const cooldownTicks = cooldown?.cooldownTicks;
                    const remainingCooldown = cooldown?.getCooldownTicksRemaining(source);

                    if (remainingCooldown == cooldownTicks - 1) {
                        cooldown.startCooldown(source);

                        source.applyKnockback(
                            direction.x,
                            direction.z,
                            10,
                            (-rotation.x / 45) * 1.2
                        );
                    }
                }
            }
        },
    });
    const areaMining = event.itemComponentRegistry.registerCustomComponent("item:area_mining", {
        onMineBlock: (iEvent) => {
            const { source: player, itemStack, block, minedBlockPermutation } = iEvent;

            const direction = player.getViewDirection();
            const dimension = player.dimension;
            const location = block.location;

            for (let x = location.x - 1; x < location.x + 2; x++) {
                for (let y = location.y - 1; y < location.y + 2; y++) {
                    for (let z = location.z - 1; z < location.z + 2; z++) {
                        if (y > -63) {
                            const currBlock = dimension.getBlock({ x, y, z });

                            if (currBlock.location.y > -63) {
                                if (currBlock.typeId != "minecraft:bedrock") {
                                    dimension.runCommandAsync(
                                        `setblock ${currBlock.location.x} ${currBlock.location.y} ${currBlock.location.z} air destroy`
                                    );
                                }
                            }
                        }
                    }
                }
            }
        },
    });
});

world.afterEvents.entityHitEntity.subscribe((event) => {
    const { hitEntity, damagingEntity } = event;

    if (damagingEntity) {
        if (damagingEntity instanceof Player) {
            const equipment = damagingEntity.getComponent("minecraft:equippable");

            const heldItem = equipment.getEquipment(EquipmentSlot.Mainhand);

            if (heldItem) {
                if (hitEntity.typeId != "ns_ma:ghost") {
                    if (heldItem.typeId == "ns_ma:spiritual_sword") {
                        hitEntity?.setDynamicProperty("SummonGhostOnDie", true);
                    } else {
                        hitEntity?.setDynamicProperty("SummonGhostOnDie", false);
                    }
                }
            }
        }
    }
});

world.afterEvents.entityDie.subscribe((event) => {
    const { deadEntity, damageSource } = event;

    const cause = damageSource.cause;
    const damagingEntity = damageSource.damagingEntity;

    if (deadEntity) {
        try {
            const location = deadEntity?.location;
            const dimension = deadEntity?.dimension;

            if (deadEntity.getDynamicProperty("SummonGhostOnDie")) {
                const ghost = dimension.spawnEntity("ns_ma:ghost", location);
                ghost.triggerEvent("ns_ma:passive");
            }
        } catch (e) {}
    }
});

/* world.afterEvents.entityHurt.subscribe((event) => {
    const { hurtEntity, damageSource } = event;

    const cause = damageSource.cause;
    const damagingEntity = damageSource.damagingEntity;
    const location = hurtEntity?.location;
    const hurtEntityHealth = hurtEntity.getComponent("minecraft:health").currentValue;

    if (damagingEntity) {
        if (damagingEntity instanceof Player) {
            const equipment = damagingEntity.getComponent("minecraft:equippable");

            const heldItem = equipment.getEquipment(EquipmentSlot.Mainhand);

            if (heldItem) {
                if (heldItem.typeId == "ns_ma:spiritual_sword") {
                    if (hurtEntityHealth < 1) {
                        const ghost = damagingEntity.dimension.spawnEntity("ns_ma:ghost", location);
                        ghost.triggerEvent("ns_ma:passive");
                    }
                }
            }
        }
    }
}); */

/**
 *
 * @param {Block} block
 * @returns
 */
function capitate(block) {
    if (!block) return;

    const logs = getConnectedLogs(block);

    breakLog(logs);
}

/**
 *
 * @param {Block} block
 * @returns
 */
function isLog(block) {
    if (!block) return;
    return block.getTags().some((tag) => tag == "log") || block.typeId.endsWith("log");
}

/**
 *
 * @param {Block} block
 * @returns
 */
function getConnectedLogs(block) {
    if (!block) return;

    const logs = [];

    for (let x = -2; x < 2; x++) {
        for (let y = -2; y < 2; y++) {
            for (let z = -2; z < 2; z++) {
                const nearBlock = block.offset({
                    x,
                    y,
                    z,
                });

                if (isLog(nearBlock)) {
                    logs.push(nearBlock);
                }
            }
        }
    }

    return logs;
}

/**
 *
 * @param {Block []} blocks
 * @returns
 */
function breakLog(blocks) {
    if (blocks.length > 0) {
        const block = blocks.pop();
        const blockLocation = block.location;
        const blockDimension = block.dimension;

        const logs = getConnectedLogs(block);

        const blocksAround = blocks.concat(logs).filter((b) => isLog(b));

        system.runTimeout(() => {
            blockDimension.runCommandAsync(
                `setblock ${blockLocation.x} ${blockLocation.y} ${blockLocation.z} air destroy`
            );
            breakLog(blocksAround);
        }, 0.05 * 20);
    }
}

function applyInvisibility(player) {
    player.addEffect("invisibility", 30 * 20, {
        showParticles: false,
    });
}

function staffShoot(player) {
    const equipment = player.getComponent("minecraft:equippable");

    const heldItem = equipment.getEquipment(EquipmentSlot.Mainhand);

    if (player.isSneaking) {
        if (heldItem) {
            changeStaffElement(player);
        }
    } else {
        if (heldItem) {
            changeStaffElement(player);

            const element = getStaffElement(heldItem);

            switch (element) {
                case "Water":
                    shootProjectile(player, "ns_ma:water_projectile", {
                        power: 1.5,
                        sound: "mob.blaze.shoot",
                    });
                    break;
                case "Fire":
                    shootProjectile(player, "ns_ma:fire_projectile", {
                        power: 1.5,
                        sound: "mob.blaze.shoot",
                    });
                    break;
                case "Lightning":
                    shootProjectile(player, "ns_ma:lightning_projectile", {
                        power: 1.5,
                        sound: "mob.blaze.shoot",
                    });
                    break;
                case "Explosion":
                    shootProjectile(player, "ns_ma:explosion_projectile", {
                        power: 1.5,
                        sound: "mob.blaze.shoot",
                    });
                    break;

                default:
                    break;
            }
        }
    }
}

function changeStaffElement(player) {
    const Elements = ["Water", "Fire", "Lightning", "Explosion"];

    const equipment = player.getComponent("minecraft:equippable");

    const heldItem = equipment.getEquipment(EquipmentSlot.Mainhand);

    if (heldItem) {
        const lore = heldItem.getLore();

        const newItem = heldItem.clone();

        if (player.isSneaking) {
            if (lore.length > 0) {
                const currentElement = lore[0];

                const currentElementIndex = Elements.indexOf(currentElement);

                if (currentElementIndex > -1) {
                    const nextElement =
                        currentElementIndex < Elements.length - 1
                            ? Elements[currentElementIndex + 1]
                            : Elements[0];

                    newItem.setLore([nextElement]);

                    equipment.setEquipment(EquipmentSlot.Mainhand, newItem);

                    displayStaffElement(player, newItem);
                }
            } else {
                newItem.setLore([Elements[0]]);

                equipment.setEquipment(EquipmentSlot.Mainhand, newItem);
            }
        } else {
            if (lore.length == 0) {
                newItem.setLore([Elements[0]]);

                equipment.setEquipment(EquipmentSlot.Mainhand, newItem);

                displayStaffElement(player, newItem);
            }
        }
    }
}

function getStaffElement(itemStack) {
    if (itemStack.typeId == "ns_ma:magical_staff") {
        const lore = itemStack.getLore();

        if (lore.length == 0) return "None";

        return itemStack.getLore()[0];
    }
}

function displayStaffElement(player, itemStack) {
    const element = getStaffElement(itemStack);

    if (element == "None") return;
    player.onScreenDisplay.setActionBar(`Element: ` + element);
}

function applyFreeze(entity) {
    entity.addEffect("slowness", 2 * 20, {
        showParticles: false,
        amplifier: 255,
    });
}

function summonMinions(player) {
    const minions = ["ns_ma:mummy", "ns_ma:vampire", "ns_ma:yeti"];

    const dimension = player.dimension;

    minions.forEach((mob) => {
        const minion = dimension.spawnEntity(mob, {
            x: player.location.x + getRandomBetween(-2, 2),
            y: player.location.y,
            z: player.location.z + getRandomBetween(-2, 2),
        });
        minion.triggerEvent("ns_ma:passive");
    });
}

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

    for (let player of players) {
        const heldItem = player
            .getComponent("minecraft:equippable")
            .getEquipment(EquipmentSlot.Mainhand);

        if (heldItem) {
            if (heldItem.typeId == "ns_ma:ice_sword") {
                const mobsOnRange = player.dimension.getEntities({
                    location: player.location,
                    families: ["monster"],
                    maxDistance: 12,
                });

                mobsOnRange.forEach((monster) => applyFreeze(monster));
            }
            if (heldItem.typeId == "ns_ma:magical_staff") {
                const element = getStaffElement(heldItem);
                player.onScreenDisplay.setActionBar(
                    `§3Element§r: ${element}\n§3Shoot§r: Right Click | Hold\n§3Change Element§r: Crouch + Right Click | Hold`
                );
            }

            if (heldItem.typeId == "ns_ma:deep_sea_trident") {
                if (player.isInWater) {
                    player.addEffect("strength", 1 * 20, {
                        amplifier: 1,
                        showParticles: false,
                    });
                    player.addEffect("speed", 1 * 20, {
                        amplifier: 1,
                        showParticles: false,
                    });
                    player.addEffect("water_breathing", 1 * 20, {
                        amplifier: 1,
                        showParticles: false,
                    });
                }
            }
        }
    }
}, 0 * 20);
