import { world } from "@minecraft/server";

world.afterEvents.itemUse.subscribe((data) => {
	const item = data.itemStack;
	const player = data.source;
	if (item.typeId === `manalabs_opw:pyro_bow`) {
		player.playAnimation(`animation.manalabs_opw.pyro_player_draw`, {
			nextState: `none`,
			blendOutTime: 0.1,
			stopExpression: `query.main_hand_item_use_duration == 0`,
			controller: `controller_name1`,
		});
	}
});

world.afterEvents.projectileHitEntity.subscribe((data) => {
	try {
		const { source: attacker, projectile } = data;
		const victim = data.getEntityHit().entity;
		const playerEquippableComp = attacker.getComponent("equippable");
		if (!playerEquippableComp) return;
		const heldBow = playerEquippableComp.getEquipment("Mainhand");
		if (!heldBow) return;
		const playerName = attacker.name;
		const notTarget = [
			"minecraft:item",
			"minecraft:armor_stand",
			"minecraft:xp_orb",
			"minecraft:arrow",
			"manalabs_opw:mini_snow_golem",
			"manalabs_opw:shadow_vex",
			"manalabs_opw:spell_amethyst",
			"manalabs_opw:spell_bubble",
			"manalabs_opw:spell_cactus",
			"manalabs_opw:spell_ice",
			"manalabs_opw:spell_laser",
			"manalabs_opw:spell_poison",
			"manalabs_opw:spell_shadow",
			"manalabs_opw:spell_skull",
		];
		//If hit, play the ping sound
		if (
			heldBow.typeId === "manalabs_opw:pyro_bow" &&
			projectile.typeId == "minecraft:arrow"
		) {
			let attackers = world.getAllPlayers();
			for (let attacker of attackers) {
				attacker.runCommand("playsound note.bell @s ~~~ 5 1.5");
				victim.setOnFire(5, true);
				victim.applyKnockback(0, 0, 0, 1);
				victim.runCommandAsync(`damage @s 3 contact`);
				victim.runCommandAsync(
					`particle minecraft:huge_explosion_lab_misc_emitter ~ ~0.5 ~`,
				);
				victim.runCommandAsync(
					`execute at @s positioned ~~-1~ run function manalabs/opw/break_blocks`,
				);
				victim.runCommandAsync(
					`playsound manalabs_opw.pyrobow_explosion @a[r=12] ~~~ 1 1`,
				);

				// This returns if playerEquippableComp is undefined.
				if (!playerEquippableComp) return;

				// This retrieves the enchantable component of the item.
				const itemEnchantmentComp = item.getComponent("minecraft:enchantable");
				const unbreakingLevel =
					itemEnchantmentComp?.getEnchantment("unbreaking")?.level ?? 0;

				// Calculates the chance of an item breaking based on its unbreaking level. This is the vanilla unbreaking formula.
				const breakChance = 100 / (unbreakingLevel + 1);
				// Generates a random chance value between 0 and 100.
				const randomizeChance = Math.random() * 100;

				// This returns if breakChance is less than randomizeChance.
				if (breakChance < randomizeChance) return;

				// This retrieves the durability component of the item.
				const itemDurabilityComp = item.getComponent("durability");

				// This returns if itemDurabilityComp is undefined.
				if (!itemDurabilityComp) return;

				// This will set the new durability value.
				itemDurabilityComp.damage += 1;

				// Declares and checks if the item is out of durability
				const maxDurability = itemDurabilityComp.maxDurability;
				const currentDamage = itemDurabilityComp.damage;
				if (currentDamage >= maxDurability) {
					// If the item is out of durability, plays the item breaking sound and removes the item
					player.playSound("random.break", {
						pitch: 1,
						location: player.location,
						volume: 1,
					});
					playerEquippableComp.setEquipment(
						"Mainhand",
						new ItemStack("minecraft:air", 1),
					);
				} else if (currentDamage < maxDurability) {
					// This sets the item in the player's selected slot.
					playerEquippableComp.setEquipment("Mainhand", item);
				}

				//Get entities within range
				const entities = victim.dimension.getEntities({
					location: {
						x: victim.location.x,
						y: victim.location.y,
						z: victim.location.z,
					},
					maxDistance: 4,
				});
				//Run code for each entity
				entities.forEach((entity) => {
					//Ignore source player and not target array
					if (entity.name == playerName) return;
					if (notTarget.includes(entity.typeId)) return;
					//Commands to run
					entity.runCommandAsync(`damage @s 4 contact`);
					entity.setOnFire(5, true);
					entity.applyKnockback(
						entity.location.x - victim.location.x,
						entity.location.z - victim.location.z,
						2,
						1,
					);
					entity.runCommandAsync(`playsound random.explode @a[r=20] ~~~ 0.3 1`);
				});
			}
		}
	} catch (error) {}
});

//If arrow hits a block - still explode
world.afterEvents.projectileHitBlock.subscribe((data) => {
	try {
		const player = data.source;
		//Get player name to filter out when ability triggers
		const playerName = player.name;
		//Array of entities to ignore
		const notTarget = [
			"minecraft:item",
			"minecraft:armor_stand",
			"minecraft:xp_orb",
			"minecraft:arrow",
			"manalabs_opw:mini_snow_golem",
			"manalabs_opw:shadow_vex",
			"manalabs_opw:spell_amethyst",
			"manalabs_opw:spell_bubble",
			"manalabs_opw:spell_cactus",
			"manalabs_opw:spell_ice",
			"manalabs_opw:spell_laser",
			"manalabs_opw:spell_poison",
			"manalabs_opw:spell_shadow",
			"manalabs_opw:spell_skull",
		];
		//Check item
		const { source: attacker, projectile } = data;
		const playerEquippableComp = attacker.getComponent("equippable");
		if (!playerEquippableComp) return;
		const heldBow = playerEquippableComp.getEquipment("Mainhand");
		if (!heldBow) return;

		if (
			heldBow.typeId === "manalabs_opw:pyro_bow" &&
			projectile.typeId == "minecraft:arrow"
		) {
			projectile.runCommandAsync(
				`particle minecraft:huge_explosion_lab_misc_emitter ~ ~0.5 ~`,
			);
			projectile.runCommandAsync(`function manalabs/opw/break_blocks`);
			projectile.runCommandAsync(`playsound random.explode @a[r=20] ~~~ 0.3 1`);
			projectile.runCommandAsync(
				`playsound manalabs_opw.pyrobow_explosion @a[r=12] ~~~ 1 1`,
			);
			projectile.runCommandAsync(`tp ~~-500~`);
			//Get entities within range
			const entities = projectile.dimension.getEntities({
				location: {
					x: projectile.location.x,
					y: projectile.location.y,
					z: projectile.location.z,
				},
				maxDistance: 4,
			});
			//Run code for each entity
			entities.forEach((entity) => {
				//Ignore source player and not target array
				if (entity.name == playerName) return;
				if (notTarget.includes(entity.typeId)) return;
				//Commands to run
				entity.runCommandAsync(`damage @s 6 contact`);
				entity.setOnFire(5, true);
				entity.applyKnockback(
					entity.location.x - projectile.location.x,
					entity.location.z - projectile.location.z,
					2,
					1,
				);
			});
			return;
		}
	} catch (error) {}
});
