import {system,Player,ItemStack,Dimension,BlockVolume} from '@minecraft/server';
import {ActionFormData,MessageFormData,ModalFormData} from "@minecraft/server-ui";
import {effects} from './config.js';

Object.defineProperties(Player.prototype, {
	removeExp: {
		value: function(amount) {
			const newAmount = this.getTotalXp() - amount;
			this.resetLevel();
			this.addExperience(newAmount);
		},
		writable: true,
		configurable: true,
		enumerable: false
	},
	skillUp: {
		value: function(skillTypeId) {
			const expRequirements = [7, 16, 27, 40, 55, 72, 91, 112, 135, 160, 187, 216, 247, 280, 315, 352, 394, 441, 493, 550, 612, 679, 751, 828, 910, 997, 1089, 1186, 1288, 1395, 1507, 1628];
			const xpRequired = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32];
			const skillIncrement = skillTypeId == 'Vitality' ? this.getProperty('dlcraft:vitality') : this.getDynamicProperty(`${skillTypeId}`) ?? 0;
			const requiredXp = expRequirements[skillTypeId == 'Vitality' ? skillIncrement - 9 : skillIncrement];
			if (skillIncrement < 32 && this.getTotalXp() >= requiredXp) {
				this.removeExp(requiredXp);
				skillTypeId == 'Vitality' ? this.setProperty('dlcraft:vitality',skillIncrement + 1) : this.setDynamicProperty(`${skillTypeId}`, skillIncrement + 1);
			} else if (skillIncrement < 32 && this.getTotalXp() < requiredXp) {
				const requiredXpMessage = xpRequired[skillTypeId == 'Vitality' ? skillIncrement - 9 : skillIncrement];
				this.onScreenDisplay.setActionBar(`§4Required §f${requiredXpMessage} Levels of Experience`);
			} else {
				this.onScreenDisplay.setActionBar(`§aMaxed the §r${skillTypeId} Skill`);
			}
		},
		writable: true,
		configurable: true,
		enumerable: false
	}
});
Object.defineProperties(ItemStack.prototype, {
	durabilityModifier: {
		value: function(player, hand, amount = 1) {
			// This returns if itemUsed is undefined or if the player is in Creative.
			if (!this || player.getGameMode() == 'creative' || player.typeId != 'minecraft:player') return;

			// This retrieves the player's equippable component.
			const playerEquippableComp = player.getComponent("equippable");

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

			// This retrieves the enchantable component of the item.
			const itemEnchantmentComp = this.getComponent("minecraft:enchantable");

			// Calculates the chance of an item breaking based on its unbreaking level. This is the vanilla unbreaking formula.
			const unbreakingLevel = itemEnchantmentComp?.getEnchantment("unbreaking")?.level ?? 0;
			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 itemUsedDurabilityComp = this.getComponent("durability");

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

			// This defines durability modification
			let durabilityModifier = amount;

			// This will set the new durability value.
			itemUsedDurabilityComp.damage += durabilityModifier;

			// Declares and checks if the item is out of durability
			const maxDurability = itemUsedDurabilityComp.maxDurability
			const currentDamage = itemUsedDurabilityComp.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(hand, undefined);
			} else if (currentDamage < maxDurability) {

				// This sets the item in the player's selected slot.

				playerEquippableComp.setEquipment(hand, this);
			}
		},
		writable: true,
		configurable: true,
		enumerable: false
	},
	amountDecrease: {
		value: function(player, hand, amountValue = 1, sound = true) {
			if (!this || player.getGameMode() == 'creative' || player.typeId != 'minecraft:player') return;
			let playerEquSlot = player.getComponent("equippable")
			if (this.amount == 1) {
				if (sound) player.dimension.playSound('random.break', player.location);
				playerEquSlot.setEquipment(hand, undefined)
			} else {
				this.amount -= amountValue
				playerEquSlot.setEquipment(hand, this)
			}
		},
		writable: true,
		configurable: true,
		enumerable: false
	}
});
Object.defineProperties(Dimension.prototype, {
	spawnLoot: {
		value: function(loot, location) {
	try {
        let randomChance = 0,
        weight = 100,
        spawnedItems = [];
        
        // Starts the loot table spawn, from the first pool
        for(const pool of loot.pools) {
            randomChance = Math.ceil(Math.random()*100);
            weight = pool?.weight ?? 100;
            // Skip if rolls does not exist
            if(!pool?.rolls) {
                console.error(`/'rolls/' is missing at pools[${loot.pools.indexOf(pool)}]`);
                continue;
            }
            if(randomChance <= weight) {
                let rolls = typeof pool.rolls === 'number' ? pool.rolls : typeof pool.rolls === 'object' ? Math.floor(Math.random()*(pool.rolls.max - pool.rolls.min + 1)) + pool.rolls.min : 1;
                rolls = rolls <= 0 ? 1 : rolls
                
                // Repeat the loot table according to the number of rolls
                for(let i = 0; i < rolls; i++) {
                    for(const entry of pool.entries) {
                        // The chance is calculated for each entry
                        randomChance = Math.ceil(Math.random()*100);
                        weight = entry?.weight ?? 100;
                        
                        if(randomChance <= weight) {
                            // Skip/Break if entry does not have an item (empty loot)
                            if(!entry?.item && entry?.stop) break;
                            if(!entry?.item) continue;
                            
                            // Gets the itemStack and count, skip if count <= 0.
                            const count = typeof entry.count === "number" ? entry.count : typeof entry.count === "object" ? Math.floor(Math.random()*(entry.count.max - entry.count.min +1)) + entry.count.min : 1;
                            if(count <= 0) continue;
                            const item = new ItemStack(`${entry.item}`, count);
                            
                            // Sets optional item parameters
                            item.setCanDestroy(entry?.canDestroy);
                            item.setCanPlaceOn(entry?.canPlaceOn);
                            item.nameTag = entry?.setName;
                            item.setLore(entry?.setLore);
                            
                            // set durability ?
                            if(entry?.setDurability && item?.getComponent('durability')) {
                                const durability = typeof entry.setDurability === 'number' ? entry.setDurability : typeof entry.setDurability === 'object' ? Math.floor(Math.random()*(entry.setDurability.max - entry.setDurability.min +1)) + entry.setDurability.min : 1,
                                maxDurability = item.getComponent('durability').maxDurability,
                                damage = durability - maxDurability;
                                item.getComponent('durability').damage += damage < 0 ? damage*-1 : damage
                            }
                            
                            // set enchantments ?
                            if(entry?.setEnchantments && item?.getComponent('enchantable')) {
                                for(const enchantment of entry.setEnchantments) {
                                    randomChance = Math.ceil(Math.random()*100);
                                    weight = enchantment?.weight ?? 100;
                                    if(randomChance <= weight) {
                                        const lvl = typeof enchantment.level === 'number' ? enchantment.level : typeof enchantment.level === 'object' ? Math.floor(Math.random()*(enchantment.level.max - enchantment.level.min +1)) + enchantment.level.min : 1;
                                        item.getComponent('enchantable').addEnchantment({ type: new EnchantmentType(`${enchantment.name}`), level: lvl });
                                        if(enchantment?.stop) break;
                                    }
                                }
                            }
                        
                            // set dynamic properties ?
                            if(entry?.setDynamicProperties && !item.isStackable) {
                                for(const property of entry.setDynamicProperties) {
                                    randomChance = Math.ceil(Math.random()*100);
                                    weight = property?.weight ?? 100;
                                    if(randomChance <= weight) {
                                        if(!property?.identifier) continue;
                                        const value = property?.value ?? null;
                                        item.setDynamicProperty(property.identifier, value);
                                        if(property?.stop) break;
                                    }
                                }
                            }
                        
                            // Spawns the item at the specified location.
                            spawnedItems.push(this.spawnItem(item, location));
                            if(entry?.stop) break;
                        }
                    }
                }
                if(pool?.stop) break;
            }
        }
        // Returns all spawned items in an entity array
        return spawnedItems;
    } catch (error) {
        console.error(error);
    }
		},
		writable: true,
		configurable: true,
		enumerable: false
	}
});

const addReqLore = (req, player, inv, item, i) => {
	const loreArr = item.getLore();
	const skill = player.getDynamicProperty(req.skill) ?? 0;
	const newLoreEntry = skill >= req.level 
	? `§2${req.skill}: §f${req.level}` 
	: `§2${req.skill}: §c${req.level}`;

	// Check if this requirement already exists in the lore
	const existingIndex = loreArr.findIndex(line => line.startsWith(`§2${req.skill}:`));

	if (existingIndex !== -1) {
		// Update existing lore
		loreArr[existingIndex] = newLoreEntry;
	} else {
		// Add new lore
		loreArr.push(newLoreEntry);
	}
	item.setLore(loreArr);
	inv.setItem(i, item);
}

const cancelEvent = (source, player, e, sourceName = 'item') => {
	if (!source) return;
	if (Array.isArray(source.requirements)) {
		let inBetweenText = '';
		source.requirements.forEach((req, index) => {
			const skill = player.getDynamicProperty(req.skill) ?? 0;
			inBetweenText += `${req.skill} ${req.level}`;
			if (index < source.requirements.length - 1) inBetweenText += ' & ';
			if (source && skill < req.level) {
				e.cancel = true;
				system.run(() => {
					player.onScreenDisplay.setActionBar(`§4Required §9Knowledge of ${inBetweenText} §fto use the ${sourceName}`);
				});
				return;
			}
		});
	} else {
		const skill = player.getDynamicProperty(source.requirements.skill) ?? 0;
		if (source && skill < source.requirements.level) {
			e.cancel = true;
			system.run(() => {player.onScreenDisplay.setActionBar(`§4Required §9Knowledge of ${source.requirements.skill} ${source.requirements.level} §fto use the ${sourceName}`);});
			return;
		}
	}
}

const cancelArmorEquipment = (source, player, equipSlot, equipSlotString) => {
	if (!source) return;
	if (Array.isArray(source.requirements)) {
		let inBetweenText = '';
		let meetsRequirements = true;
		source.requirements.forEach((req, index) => {
			const skill = player.getDynamicProperty(req.skill) ?? 0;
			inBetweenText += `${req.skill} ${req.level}`;
			if (index < source.requirements.length - 1) inBetweenText += ' & ';
			if (source && skill < req.level) meetsRequirements = false;
		});
		if (!meetsRequirements) {
			player.getComponent('equippable').setEquipment(equipSlotString, undefined);
			player.dimension.spawnItem(equipSlot, player.location);
			player.onScreenDisplay.setActionBar(`§4Required §9Knowledge of ${inBetweenText} §fto use the item`);
		}
	} else {
		const skill = player.getDynamicProperty(source.requirements.skill) ?? 0;
		if (source && skill < source.requirements.level) {
			player.getComponent('equippable').setEquipment(equipSlotString, undefined);
			player.dimension.spawnItem(equipSlot, player.location);
			player.onScreenDisplay.setActionBar(`§4Required §9Knowledge of ${source.requirements.skill} ${source.requirements.level} §fto use the item`);
		}
	}
}

const classSelection = (player) => {
	const form = new ActionFormData()
	.title('Create Character')
	.body('Select Class')
	.button('Knight')
	.button('Magician')
	.button('Barbarian')
	.button('Hunter')
	.button('Soldier');
	const confirmForm = new MessageFormData();
	confirmForm.title('Confirm to select this class');	
	confirmForm.button1('§fReturn');
	confirmForm.button2(`§fConfirm`);
	forceShow(player, form).then((response) => {
		if (response.canceled && response.cancelationReason == 'UserBusy') return form.show(player);
		switch (response.selection) {
			case 0:
				confirmForm.body('§r§fKnight Class\n\n§fCombat: §74\n§fWeaponry: §72\n§fDefense: §74\n\n§fArmor: §7Chainmail Helmet\n§7Chainmail Chestplate\n\n§fWeapon: §7Wooden Sabre');
				confirmForm.show(player).then((response) => {
					if (response.selection == 1) {
						player.setDynamicProperty('Class', 'Knight');
						player.setDynamicProperty('Combat', 4);
						player.setDynamicProperty('Defense', 4);
						player.setDynamicProperty('Weaponry', 2);
						player.getComponent('equippable').setEquipment('Head', new ItemStack('minecraft:chainmail_helmet'));
						player.getComponent('equippable').setEquipment('Chest', new ItemStack('minecraft:chainmail_chestplate'));
						player.dimension.spawnItem(new ItemStack('btr:wooden_sabre'), player.location);
					} else classSelection(player);
				});
				break;
			case 1:
				confirmForm.body('§r§fMagician Class\n\n§fVitality: §79\n§fEnder: §78\n§fCombat: §72\n\n§fArmor: §7Leather Leggings\n\n§fWeapon: §7Wooden Bo');
				confirmForm.show(player).then((response) => {
					if (response.selection == 1) {
						player.setDynamicProperty('Class', 'Magician');
						player.setProperty('dlcraft:vitality', 9);
						player.setDynamicProperty('Ender', 8);
						player.setDynamicProperty('Combat', 2);
						player.getComponent('equippable').setEquipment('Legs', new ItemStack('minecraft:leather_leggings'));
						player.dimension.spawnItem(new ItemStack('btr:wooden_bo'), player.location);
					} else classSelection(player);
				});
				break;
			case 2:
				confirmForm.body('§r§fBarbarian Class\n\n§fVitality: §713\n\n§fArmor: §7Leather Leggings\n\n§fWeapon: §7Studded Club');
				confirmForm.show(player).then((response) => {
					if (response.selection == 1) {
						player.setDynamicProperty('Class', 'Barbarian');
						player.setProperty('dlcraft:vitality', 13);
						player.getComponent('equippable').setEquipment('Legs', new ItemStack('minecraft:leather_leggings'));
						player.dimension.spawnItem(new ItemStack('btr:studded_club'), player.location);
					} else classSelection(player);
				});
				break;
			case 3:
				confirmForm.body('§r§fHunter Class\n\n§fVitality: §711\n§fDefense: §71\n§fWeaponry: §78\n\n§fArmor: §7Leather Chestplate\n\n§fWeapon: §7Wooden Battleaxe');
				confirmForm.show(player).then((response) => {
					if (response.selection == 1) {
						player.setDynamicProperty('Class', 'Hunter');
						player.setProperty('dlcraft:vitality', 11);
						player.setDynamicProperty('Defense', 1);
						player.setDynamicProperty('Weaponry', 8);
						player.getComponent('equippable').setEquipment('Chest', new ItemStack('minecraft:leather_chestplate'));
						player.dimension.spawnItem(new ItemStack('btr:wooden_battleaxe'), player.location);
					} else classSelection(player);
				});
				break;
			case 4:
				confirmForm.body('§r§fSoldier Class\n\n§fVitality: §712\n§fCombat: §72\n§fWeaponry: §72\n§fDefense: §72\n\n§fArmor: §7Leather Helmet\n§7Leather Leggings\n\n§fWeapon: §7Wooden Sabre');
				confirmForm.show(player).then((response) => {
					if (response.selection == 1) {
						player.setDynamicProperty('Class', 'Soldier');
						player.setProperty('dlcraft:vitality', 12);
						player.setDynamicProperty('Defense', 2);
						player.setDynamicProperty('Combat', 2);
						player.setDynamicProperty('Weaponry', 2);
						player.getComponent('equippable').setEquipment('Head', new ItemStack('minecraft:leather_helmet'));
						player.getComponent('equippable').setEquipment('Legs', new ItemStack('minecraft:leather_leggings'));
						player.dimension.spawnItem(new ItemStack('btr:wooden_sabre'), player.location);
					} else classSelection(player);
				});
				break;
			default: break;
		}
	});
};

async function forceShow(player, form, timeout = Infinity) {
    const startTick = system.currentTick;
    while ((system.currentTick - startTick) < timeout) {
        const response = await form.show(player);
        if (response.cancelationReason !== 'UserBusy') {
            return response;
        };
    };
    throw new Error(`Timed out after ${timeout} ticks`);
};

const randomWholeNum = (min, max) => {
    const maxPlus1 = max + 1;
    let result = Math.random() * (max - min) + min;
    //return a random whole number
    return Math.round(result);
};

const randomNumber = (min, max) => {
	return Math.floor(Math.random() * max - min) + min
};

export default class Utils {
  /**
   * @param {Entity} entity
   */
  constructor(entity) {
    this.entity = entity;
    this.rideable = entity?.getComponent('rideable');
    this.player = this.rideable?.getRiders()[0];
    this.riding = this.player?.getComponent('riding');
  }

  /**
   * @param {number} flySpeed
   * @param {number} fallSpeed
   */
  flySystem(flySpeed, fallSpeed, XZspeed) {
    if (!this.riding) return;
    const direction = {
      x: 0,
      y: this.player.isJumping ? flySpeed : fallSpeed,
      z: 0,
    };
    this.entity.addEffect('speed', 5, {
      showParticles: false,
      amplifier: XZspeed,
    });
    this.entity.applyImpulse(direction);
  }
}

const integerToRoman = (num) => {
    const romanValues = {
        M: 1000,
        CM: 900,
        D: 500,
        CD: 400,
        C: 100,
        XC: 90,
        L: 50,
        XL: 40,
        X: 10,
        IX: 9,
        V: 5,
        IV: 4,
        I: 1
    };
    let roman = '';
    for (let key in romanValues) {
        while (num >= romanValues[key]) {
            roman += key;
            num -= romanValues[key];
        }
    }
    return roman;
};

const shootProjectile = (player, typeId) => {
	const headLoc = player.getHeadLocation();
	const viewDir = player.getViewDirection();
	const direction = { x: headLoc.x + viewDir.x, y: headLoc.y + viewDir.y, z: headLoc.z + viewDir.z };
	const vel = { x: viewDir.x * 1, y: viewDir.y * 1, z: viewDir.z * 1 };
	const proj = player.dimension.spawnEntity(typeId, direction);
	const projectile = proj.getComponent("projectile");
	if (projectile) {
		projectile.owner = player;
		projectile.shoot(vel);
	}
};

const enchantConfirmForm = (player, playerHoldItem, enchant, entityInv, increment = false) => {
	const expRequirements = [0, 7, 16, 27, 40, 55, 72, 91, 112, 135, 160, 187, 216, 247, 280, 315, 352, 394, 441, 493, 550, 612, 679, 751, 828, 910, 997, 1089, 1186, 1288, 1395, 1507, 1628];
	const xpRequired = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32];
	const enchantIncrement = playerHoldItem.getDynamicProperty('btr:enchant') ?? 0;
	const requiredXp = expRequirements[enchant.lvl+enchantIncrement];
	const color = player.getTotalXp() >= requiredXp ? '§f' : '§c';
	const requiredXpMessage = xpRequired[enchant.lvl+enchantIncrement];
	let form = new MessageFormData();
	form.title('Cyprium');
	form.body(`Confirm to enchant your tool with §r§7${enchant.enchantmentName} ${integerToRoman(enchant.lvl)}\n§4Required ${color}${requiredXpMessage} Levels of Experience`);
	form.button1('§fCancel');
	form.button2(`${color}Confirm`);
	form.show(player).then((response) => {
		if (response.selection == 1) {
			if (player.getTotalXp() >= requiredXp) {
		const enchantDP = playerHoldItem.getDynamicProperty(enchant.enchantmentId);
      	playerHoldItem.setDynamicProperty(enchant.enchantmentId, increment ? enchantDP + 1 : enchant.lvl);
      	playerHoldItem.setDynamicProperty('btr:enchant', enchantIncrement+enchant.lvl);
      	const lvl = playerHoldItem.getDynamicProperty(enchant.enchantmentId);
      	const itemLore = playerHoldItem.getLore();
      	const existingIndex = itemLore.findIndex(line => line.startsWith(`§r§7${enchant.enchantmentName}`));
      	const lore = `§r§7${enchant.enchantmentName} ${integerToRoman(lvl)}`;
	if (existingIndex !== -1) {
		// Update existing lore
		itemLore[existingIndex] = lore;
	} else {
		// Add new lore
		itemLore.push(lore);
	}
	playerHoldItem.setLore(itemLore);
	player.getComponent('equippable').setEquipment('Mainhand', playerHoldItem);
	player.removeExp(requiredXp);
	player.dimension.playSound('random.anvil_use', player.location);
	entityInv.container.setItem(0, undefined);
      }
      else {
      	player.onScreenDisplay.setActionBar(`§4Required §f${requiredXpMessage} Levels of Experience`);
      }
		}
	});
};

// Config form
function configForm(player) {
	const status = player.getStatus();
	const op = player.isOp();
	let formValuesPush = 0;
	
    let form = new ModalFormData()
    .title({translate:"sweepnslash.configmenutitle"})
    if (op == true) {
    	form.toggle({translate:"sweepnslash.toggledebugmode"}, world.getDynamicProperty("debug_mode"));
    }
    
    form.toggle({translate:"sweepnslash.excludepetfromsweep"}, player.getDynamicProperty("excludePetFromSweep")??false);
    form.dropdown({translate:"sweepnslash.indicatorstyle"}, [{translate:"sweepnslash.crosshair"}, {translate:"sweepnslash.hotbar"}, {translate:"sweepnslash.none"}], player.getDynamicProperty("cooldownStyle"));
    form.toggle({translate:"sweepnslash.sweepparticles"}, player.getDynamicProperty("sweep")??false);
    form.toggle({translate:"sweepnslash.enchantedhitparticles"}, player.getDynamicProperty("enchantedHit")??false);
    form.toggle({translate:"sweepnslash.damageindicatorparticles"}, player.getDynamicProperty("damageIndicator")??false);
    form.toggle({translate:"sweepnslash.critparticles"}, player.getDynamicProperty("criticalHit")??false);
    form.toggle({translate:"sweepnslash.critsounds"}, player.getDynamicProperty("critSound")??false);
    
    form.textField({rawtext:[{text:"\n"},{translate:"sweepnslash.sweepRGBtitle"},{text:"\n\n"},{text:"R"}]}, "0~255", JSON.stringify(player.getDynamicProperty('sweepR')??255));
    form.textField("G", "0~255", JSON.stringify(player.getDynamicProperty('sweepG')??255));
    form.textField("B", "0~255", JSON.stringify(player.getDynamicProperty('sweepB')??255));
    
    form.submitButton({translate:"sweepnslash.saveconfig"});
    
    form.show(player).then((response) => {
        const { canceled, formValues, cancelationReason } = response;
        
        function n(value) {
        	const num = Number(value);
	        if (isNaN(value)) player.sendMessage({translate:"sweepnslash.nan"})
	        return isNaN(num) ? 0 : num
        }
        
        function valuePush(object, dynamicProperty, push, isRgb) {
        	// If condition is passed, push the responses
			if (push == true) {
				object.setDynamicProperty(dynamicProperty,isRgb?clamp(n(formValues[formValuesPush]), 0, 255):formValues[formValuesPush]);
				formValuesPush++
	        }
	    };
        if (response && canceled && cancelationReason === "UserBusy") {
            configForm(player);
            return;
        }
        if (canceled) {
        	player.sendMessage({translate:"sweepnslash.canceled"});
	        return;
        } else if (!canceled) {
        	player.sendMessage({translate:"sweepnslash.saved"});
        }
        
        if (!world.isHardcore) valuePush(world, "addon_toggle", op);
        valuePush(world, "debug_mode", op);
        
        valuePush(player, "excludePetFromSweep", true);
        valuePush(player, "cooldownStyle", true);
        valuePush(player, "sweep", true);
        valuePush(player, "enchantedHit", true);
        valuePush(player, "damageIndicator", true);
        valuePush(player, "criticalHit", true);
        valuePush(player, "critSound", true);
        
        valuePush(player, "sweepR", true, true);
        valuePush(player, "sweepG", true, true);
        valuePush(player, "sweepB", true, true);
        
    })
}

const applyEffect = (player, propertyName) => {
	const dynamicProperty = player.getDynamicProperty(propertyName);

	let effectValue = dynamicProperty;

	// lowest limit
	if (effectValue < -5) {
		effectValue = -5;
	}
	// highest limit
	else if (effectValue > 10) {
		effectValue = 10;
	}

	const effectData = effects[propertyName][Math.floor(effectValue).toString()];
	if (effectData) {
		player.addEffect(effectData.effectName, effectData.duration ?? 20, { amplifier: effectData.amplifier, showParticles: effectData.showParticles ?? false });
	}
};
const giveItemEffects = (items, player) => {
	const {x, y, z} = player.location;
	const blockBelowPos = {x: x, y: y - 1, z: z};

	const conditionChecks = {
		hasTag: (value) => player.hasTag(value),
		isInWater: (value) => player.isInWater === value,
		isOnGround: (value) => player.isOnGround === value,
		blockBelow: (value) => player.dimension.getBlock(blockBelowPos).typeId === value
	};

	// Check main conditions
	if (items.conditions) {
		const conditionsMet = Object.entries(items.conditions).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (conditionsMet && items.effects) {
			Object.entries(items.effects).forEach(([effectName, value]) => {
				let e = player.getDynamicProperty(effectName);
				player.setDynamicProperty(effectName, e += value);
			});
		}
	}

	// Check secondary conditions
	if (items.condition1) {
		const condition1Met = Object.entries(items.condition1).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (condition1Met && items.effects1) {
			Object.entries(items.effects1).forEach(([effectName, value]) => {
				let e = player.getDynamicProperty(effectName);
				player.setDynamicProperty(effectName, e += value);
			});
		}
	}

	if (items.condition2) {
		const condition2Met = Object.entries(items.condition2).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (condition2Met && items.effects2) {
			Object.entries(items.effects2).forEach(([effectName, value]) => {
				let e = player.getDynamicProperty(effectName);
				player.setDynamicProperty(effectName, e += value);
			});
		}
	}

	if (items.noConditions && items.effects) {
		Object.entries(items.effects).forEach(([effectName, value]) => {
			let e = player.getDynamicProperty(effectName);
			player.setDynamicProperty(effectName, e += value);
		});
	}
};
const removeItemEffects = (items, player, event) => {
	const {x, y, z} = player.location;
	const blockBelowPos = {x: x, y: y - 1, z: z};

	const conditionChecks = {
		hasTag: (value) => player.hasTag(value),
		isInWater: (value) => player.isInWater === value,
		isOnGround: (value) => player.isOnGround === value,
		blockBelow: (value) => player.dimension.getBlock(blockBelowPos).typeId === value
	};

	// Check main conditions
	if (items.conditions) {
		const conditionsMet = Object.entries(items.conditions).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (conditionsMet && items.removeEffects) {
			if (Array.isArray(items.removeEffects)) {
				items.removeEffects.forEach(effect => player.removeEffect(effect));
			} else {
				player.removeEffect(items.removeEffects);
			}
		}
	}

	// Check secondary conditions
	if (items.condition1) {
		const condition1Met = Object.entries(items.condition1).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (condition1Met && items.removeEffects1) {
			if (Array.isArray(items.removeEffects1)) {
				items.removeEffects1.forEach(effect => player.removeEffect(effect));
			} else {
				player.removeEffect(items.removeEffects1);
			}
		}
	}

	// Check secondary conditions
	if (items.condition2) {
		const condition2Met = Object.entries(items.condition2).every(([condition, value]) => {
			const check = conditionChecks[condition];
			return check ? check(value) : false;
		});

		if (condition2Met && items.removeEffects2) {
			if (Array.isArray(items.removeEffects2)) {
				items.removeEffects2.forEach(effect => player.removeEffect(effect));
			} else {
				player.removeEffect(items.removeEffects2);
			}
		}
	}

	// Handle no conditions case
	if (items.noConditions && items.removeEffects) {
		if (Array.isArray(items.removeEffects)) {
			items.removeEffects.forEach(effect => player.removeEffect(effect));
		} else {
			player.removeEffect(items.removeEffects);
		}
	}
};

const spawnerLoc = new Map();

function findBlocks(blockId, dimension, location, radius) {
    const searchVolume = new BlockVolume(
        {
            x: location.x + radius,
            y: location.y + radius,
            z: location.z + radius,
        },
        {
            x: location.x - radius,
            y: location.y - radius,
            z: location.z - radius,
        },
    );
    const blocks = dimension.getBlocks(searchVolume, {
        includeTypes: [blockId],
    });
    for (const blockLocation of blocks.getBlockLocationIterator()) {
        const block = dimension.getBlock(blockLocation);
        return block;
    };
    return false;
}

const lootTable = (location, player, lootSpawn) => {
	player.runCommandAsync(`loot spawn ${location.x} ${location.y} ${location.z} loot "${lootSpawn}"`);
};

function teleportToWorldSpawn(target, world) {
	var spawn = world.getDefaultSpawnLocation()
	const {x,y,z} = target.location;
	spawn.x += (Math.floor((Math.random() * 11) - 5))
	spawn.z += (Math.floor((Math.random() * 11) - 5))
	system.runTimeout(() => {
		target.teleport({x: spawn.x, y: 200, z: spawn.z}, {dimension: world.getDimension('overworld'), checkForBlocks: false});
		target.addEffect('resistance', 4*20, {amplifier: 255,showParticles: false});
		target.dimension.spawnParticle('happy:magic_mirror_particle_0', {x: x, y: y+1, z: z});
		target.dimension.spawnParticle('happy:magic_mirror_particle_1', {x: x, y: y+1, z: z});
		target.dimension.spawnParticle('happy:magic_mirror_particle_2', {x: x, y: y+1, z: z});
		target.dimension.playSound('random.magic_mirror_use', target.location);
	}, 1);
}

function setAttributes(item) {
	const attributes = {
		attribute: [],
		score: 0
	};
	let lore = item.getLore();
	function getRandomNumberWithDecreasingProbability(min, max, lambda) {
		function exponentialRandom(lambda2) {
			return -Math.log(1 - Math.random()) / lambda2;
		}
		const range = max - min + 1;
		let num;
		do {
			num = Math.floor(min + exponentialRandom(lambda) * range);
		} while (num < min || num > max);
		return num;
	}
	function getRandomAttackDamageBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 3);
				attributes.attribute.push(`\xA7r\xA7a\xA7t\xA7k\xA7d\xA7m\xA7g\xA7e\xA7r\xA79+${attributeValue}% Attack Damage`);
				attributes.score = attributes.score + attributeValue;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 4);
				attributes.attribute.push(`\xA7r\xA7a\xA7t\xA7k\xA7d\xA7m\xA7g\xA7e\xA7r\xA7c-${attributeValue}% Attack Damage`);
				attributes.score = attributes.score - attributeValue;
			}
		}
	}
	function getRandomProjectileDamageBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 3);
				attributes.attribute.push(`\xA7r\xA7p\xA7j\xA7t\xA7d\xA7m\xA7g\xA7e\xA7r\xA79+${attributeValue}% Projectile Damage`);
				attributes.score = attributes.score + attributeValue;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 4);
				attributes.attribute.push(`\xA7r\xA7p\xA7j\xA7t\xA7d\xA7m\xA7g\xA7e\xA7r\xA7c-${attributeValue}% Projectile Damage`);
				attributes.score = attributes.score - attributeValue;
			}
		}
	}
	function getRandomCriticalChanceBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 50, 3);
				attributes.attribute.push(`\xA7r\xA7c\xA7t\xA7c\xA7c\xA7h\xA7a\xA7n\xA7r\xA79+${attributeValue}% Critical Chance`);
				attributes.score = attributes.score + attributeValue * 2;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 50, 4);
				attributes.attribute.push(`\xA7r\xA7c\xA7t\xA7c\xA7c\xA7h\xA7a\xA7n\xA7r\xA7c-${attributeValue}% Critical Chance`);
				attributes.score = attributes.score - attributeValue * 2;
			}
		}
	}
	function getRandomCriticalDamageBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 4);
				attributes.attribute.push(`\xA7r\xA7c\xA7t\xA7c\xA7d\xA7m\xA7g\xA7e\xA7r\xA79+${attributeValue}% Critical Damage`);
				attributes.score = attributes.score + attributeValue;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 5);
				attributes.attribute.push(`\xA7r\xA7c\xA7t\xA7c\xA7d\xA7m\xA7g\xA7e\xA7r\xA7c-${attributeValue}% Critical Damage`);
				attributes.score = attributes.score - attributeValue;
			}
		}
	}
	function getRandomBlockOrParryChanceBonus() {
		if (Math.random() < 0.25) {
			if (Math.random() < 0.5) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 2);
				attributes.attribute.push(`\xA7r\xA7b\xA7l\xA7k\xA7c\xA7h\xA7a\xA7n\xA7r\xA79+${attributeValue}% Block Chance`);
				attributes.score = attributes.score + attributeValue * 5;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 3);
				attributes.attribute.push(`\xA7r\xA7p\xA7r\xA7c\xA7h\xA7a\xA7n\xA7r\xA79+${attributeValue}% Parry Chance`);
				attributes.score = attributes.score + attributeValue * 10;
			}
		}
	}
	function getRandomDamageReductionBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 3);
				attributes.attribute.push(`\xA7r\xA7d\xA7m\xA7g\xA7e\xA7r\xA7e\xA7d\xA7r\xA79+${attributeValue}% Damage Reduction`);
				attributes.score = attributes.score + attributeValue * 10;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 4);
				attributes.attribute.push(`\xA7r\xA7d\xA7m\xA7g\xA7e\xA7r\xA7e\xA7d\xA7r\xA7c-${attributeValue}% Damage Reduction`);
				attributes.score = attributes.score - attributeValue * 10;
			}
		}
	}
	function getRandomEvasionChanceBonus() {
		if (Math.random() < 0.25) {
			const attributeValue = getRandomNumberWithDecreasingProbability(1, 5, 3);
			attributes.attribute.push(`\xA7r\xA7e\xA7v\xA7c\xA7h\xA7a\xA7n\xA7r\xA79+${attributeValue}% Evasion Chance`);
			attributes.score = attributes.score + attributeValue * 10;
		}
	}
	function getRandomMiningEfficiencyBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 4);
				attributes.attribute.push(`\xA7r\xA7m\xA7i\xA7n\xA7e\xA7f\xA7f\xA7r\xA79+${attributeValue}% Mining Efficiency`);
				attributes.score = attributes.score + attributeValue;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 100, 5);
				attributes.attribute.push(`\xA7r\xA7m\xA7i\xA7n\xA7e\xA7f\xA7f\xA7r\xA7c-${attributeValue}% Mining Efficiency`);
				attributes.score = attributes.score - attributeValue;
			}
		}
	}
	function getRandomMovementSpeedBonus() {
		if (Math.random() < 0.5) {
			if (Math.random() < 0.75) {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 2);
				attributes.attribute.push(`\xA7r\xA7m\xA7o\xA7v\xA7s\xA7p\xA7r\xA79+${attributeValue}% Movement Speed`);
				attributes.score = attributes.score + attributeValue * 5;
			} else {
				const attributeValue = getRandomNumberWithDecreasingProbability(1, 10, 3);
				attributes.attribute.push(`\xA7r\xA7m\xA7o\xA7v\xA7s\xA7p\xA7r\xA7c-${attributeValue}% Movement Speed`);
				attributes.score = attributes.score - attributeValue * 5;
			}
		}
	}
	if (item.hasTag("minecraft:is_sword") && item.typeId !== "minecraft:mace") {
		getRandomAttackDamageBonus();
		getRandomCriticalChanceBonus();
		getRandomCriticalDamageBonus();
		getRandomBlockOrParryChanceBonus();
		getRandomMovementSpeedBonus();
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 100, attributes.score <= 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.typeId === "minecraft:bow" || item.typeId === "minecraft:crossbow") {
		getRandomProjectileDamageBonus();
		getRandomCriticalChanceBonus();
		getRandomCriticalDamageBonus();
		getRandomMovementSpeedBonus();
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 100, attributes.score <= 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.hasTag("minecraft:is_trident") || item.typeId === "minecraft:mace") {
		getRandomAttackDamageBonus();
		getRandomCriticalChanceBonus();
		getRandomCriticalDamageBonus();
		getRandomMovementSpeedBonus();
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 100, attributes.score <= 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.hasTag("minecraft:is_axe")) {
		getRandomAttackDamageBonus();
		getRandomCriticalChanceBonus();
		getRandomCriticalDamageBonus();
		getRandomMiningEfficiencyBonus();
		getRandomMovementSpeedBonus();
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 100, attributes.score <= 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 150) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.hasTag("minecraft:is_pickaxe") || item.hasTag("minecraft:is_shovel") || item.hasTag("minecraft:is_hoe")) {
		for (let i = 0; i < 3; i++) {
			getRandomMiningEfficiencyBonus();
			getRandomMovementSpeedBonus();
			if (attributes.attribute.length > 0) {
				break;
			}
		}
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 75) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 75, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.hasTag("minecraft:is_armor")) {
		for (let i = 0; i < 2; i++) {
			getRandomDamageReductionBonus();
			getRandomEvasionChanceBonus();
			getRandomMovementSpeedBonus();
			if (attributes.attribute.length > 0) {
				break;
			}
		}
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 75) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 75, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	if (item.typeId === "minecraft:shield") {
		for (let i = 0; i < 3; i++) {
			getRandomDamageReductionBonus();
			getRandomMovementSpeedBonus();
			if (attributes.attribute.length > 0) {
				break;
			}
		}
		if (attributes.attribute.length > 0) {
			attributes.attribute.unshift("\xA7r\xA7a\xA7d\xA7d\xA7i\xA7t\xA7i\xA7o\xA7n\xA7a\xA7l\xA7r\xA77Additional:");
			attributes.attribute.push("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		}
		if (attributes.score <= 50) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7c\xA7o\xA7m\xA7m\xA7r\xA7aCommon");
		} else if (attributes.score > 50, attributes.score <= 75) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7r\xA7a\xA7r\xA7e\xA7r\xA7bRare");
		} else if (attributes.score > 75, attributes.score <= 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7e\xA7p\xA7i\xA7c\xA7r\xA7dEpic");
		} else if (attributes.score > 100) {
			attributes.attribute.push("\xA7r\xA7r\xA7a\xA7r\xA7i\xA7t\xA7y\xA7r\xA77Rarity: \xA7r\xA7l\xA7g\xA7d\xA7r\xA7r\xA76Legendary");
		}
		attributes.attribute.unshift("\xA7r\xA7a\xA7t\xA7t\xA7r\xA7i\xA7b\xA7u\xA7t\xA7e\xA7s\xA7r");
		lore = attributes.attribute.concat(lore);
	}
	item.setLore(lore);
}

function getAttributes(player, attributes) {
	function extractNumberFromString(str) {
		const numStr = str.match(/([+-]\d+)/);
		return Number(numStr[0]);
	}
	const equippable = player.getComponent('equippable');
	const mainhand = equippable.getEquipment('Mainhand');
	const offhand = equippable.getEquipment('Offhand');
	const head = equippable.getEquipment('Head');
	const chest = equippable.getEquipment('Chest');
	const legs = equippable.getEquipment('Legs');
	const feet = equippable.getEquipment('Feet');
	const items = [mainhand,
		offhand,
		head,
		chest,
		legs,
		feet];
	for (const item of items) {
		if (item === void 0) {
			continue;
		}
		const lore = item.getLore();
		if (item === mainhand && item.hasTag("minecraft:is_armor") || item === offhand && item.hasTag("minecraft:is_armor")) {
			continue;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7a\xA7t\xA7k\xA7d\xA7m\xA7g\xA7e\xA7r")) !== void 0) {
			const attackDamageBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7a\xA7t\xA7k\xA7d\xA7m\xA7g\xA7e\xA7r")));
			attributes.attackDamage = (attributes.attackDamage * 100 + attackDamageBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7p\xA7j\xA7t\xA7d\xA7m\xA7g\xA7e\xA7r")) !== void 0) {
			const projectileDamageBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7p\xA7j\xA7t\xA7d\xA7m\xA7g\xA7e\xA7r")));
			attributes.projectileDamage = (attributes.projectileDamage * 100 + projectileDamageBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7c\xA7t\xA7c\xA7c\xA7h\xA7a\xA7n\xA7r")) !== void 0) {
			const criticalChanceBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7c\xA7t\xA7c\xA7c\xA7h\xA7a\xA7n\xA7r")));
			attributes.criticalChance = (attributes.criticalChance * 100 + criticalChanceBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7c\xA7t\xA7c\xA7d\xA7m\xA7g\xA7e\xA7r")) !== void 0) {
			const criticalDamageBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7c\xA7t\xA7c\xA7d\xA7m\xA7g\xA7e\xA7r")));
			attributes.criticalDamage = (attributes.criticalDamage * 100 + criticalDamageBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7b\xA7l\xA7k\xA7c\xA7h\xA7a\xA7n\xA7r")) !== void 0) {
			const blockChanceBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7b\xA7l\xA7k\xA7c\xA7h\xA7a\xA7n\xA7r")));
			attributes.blockChance = (attributes.blockChance * 100 + blockChanceBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7p\xA7r\xA7c\xA7h\xA7a\xA7n\xA7r")) !== void 0) {
			const parryChanceBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7p\xA7r\xA7c\xA7h\xA7a\xA7n\xA7r")));
			attributes.parryChance = (attributes.parryChance * 100 + parryChanceBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7d\xA7m\xA7g\xA7e\xA7r\xA7e\xA7d\xA7r")) !== void 0) {
			const damageReductionBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7d\xA7m\xA7g\xA7e\xA7r\xA7e\xA7d\xA7r")));
			attributes.damageReduction = (attributes.damageReduction * 100 - damageReductionBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7e\xA7v\xA7c\xA7h\xA7a\xA7n\xA7r")) !== void 0) {
			const evasionChanceBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7e\xA7v\xA7c\xA7h\xA7a\xA7n\xA7r")));
			attributes.evasionChance = (attributes.evasionChance * 100 + evasionChanceBonus) / 100;
		}
		if (lore.find((element) => element.includes("\xA7r\xA7m\xA7o\xA7v\xA7s\xA7p\xA7r")) !== void 0) {
			const movementSpeedBonus = extractNumberFromString(lore.find((element) => element.includes("\xA7r\xA7m\xA7o\xA7v\xA7s\xA7p\xA7r")));
			attributes.movementSpeed = (attributes.movementSpeed * 100 + movementSpeedBonus) / 100;
		}
	}
	const speedEffect = player.getEffect("speed");
	if (speedEffect !== void 0) {
		attributes.movementSpeed = (attributes.movementSpeed * 100 + (speedEffect.amplifier + 1) * 20) / 100;
	}
	const slownessEffect = player.getEffect("slowness");
	if (slownessEffect !== void 0) {
		attributes.movementSpeed = (attributes.movementSpeed * 100 - (slownessEffect.amplifier + 1) * 15) / 100;
	}
	if (attributes.attackDamage < 0) {
		attributes.attackDamage = 0;
	}
	if (attributes.projectileDamage < 0) {
		attributes.projectileDamage = 0;
	}
	if (attributes.criticalChance < 0) {
		attributes.criticalChance = 0;
	}
	if (attributes.criticalDamage < 1) {
		attributes.criticalDamage = 1;
	}
	if (attributes.blockChance < 0) {
		attributes.blockChance = 0;
	}
	if (attributes.parryChance < 0) {
		attributes.parryChance = 0;
	}
	if (attributes.damageReduction < 0) {
		attributes.damageReduction = 0;
	}
	if (attributes.evasionChance < 0) {
		attributes.evasionChance = 0;
	}
	if (attributes.movementSpeed < 0) {
		attributes.movementSpeed = 0;
	}
}


export {addReqLore,cancelEvent,cancelArmorEquipment,classSelection,randomWholeNum,randomNumber,Utils,integerToRoman,shootProjectile,enchantConfirmForm,configForm,applyEffect,giveItemEffects,removeItemEffects,spawnerLoc,findBlocks,lootTable,teleportToWorldSpawn,setAttributes,getAttributes};
