import { system, world, ItemStack } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";

const upgrades = [
	{
		name: "speed",
		bonus: "slowness",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // speed 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // speed 1
			{ type: "bonus", progress: 0, cost: 15 }, // slowness 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // speed 2
			{ type: "bonus", progress: 1, cost: 25 } // slowness 1
		]
	},
	{
		name: "resistance",
		bonus: "fire_aspect",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // resistance 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // resistance 1
			{ type: "bonus", progress: 0, cost: 15 }, // fire aspect 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // resistance 2
			{ type: "bonus", progress: 1, cost: 25 } // fire aspect 1
		]
	},
	{
		name: "jump_boost",
		bonus: "levitation",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // jump boost 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // jump boost 1
			{ type: "bonus", progress: 0, cost: 15 }, // levitation 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // jump boost 2
			{ type: "bonus", progress: 1, cost: 25 } // levitation 1
		]
	},
	{
		name: "haste",
		bonus: "saturation",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // haste 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // haste 1
			{ type: "bonus", progress: 0, cost: 15 }, // saturation 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // haste 2
			{ type: "bonus", progress: 1, cost: 25 } // saturation 1
		]
	},
	{
		name: "strength",
		bonus: "poison",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // strength 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // strength 1
			{ type: "bonus", progress: 0, cost: 15 }, // poison 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // strength 2
			{ type: "bonus", progress: 1, cost: 25 } // poison 1
		]
	},
	{
		name: "luck",
		bonus: "wither",
		steps: [
			{ type: "research", progress: 1, cost: 5 },
			{ type: "research", progress: 2, cost: 5 },
			{ type: "research", progress: 3, cost: 5 },
			{ type: "upgrade", progress: 0, cost: 10}, // luck 0
			{ type: "research", progress: 4, cost: 10 },
			{ type: "research", progress: 5, cost: 10 },
			{ type: "research", progress: 6, cost: 10 },
			{ type: "upgrade", progress: 1, cost: 15 }, // luck 1
			{ type: "bonus", progress: 0, cost: 15 }, // wither 0
			{ type: "research", progress: 7, cost: 20 },
			{ type: "research", progress: 8, cost: 20 },
			{ type: "research", progress: 9, cost: 20 },
			{ type: "upgrade", progress: 2, cost: 25 }, // luck 2
			{ type: "bonus", progress: 1, cost: 25 } // wither 1
		]
	}
];

let skills_min_score = {};
for (const upgrade of upgrades) {
	const upgrade_name = upgrade.name;
	skills_min_score[upgrade_name] = {};

	let step_count = 0;
	for (const step of upgrade.steps) {
		const upgrade_type = step.type;
		const upgrade_progress = step.progress;
		
		if (upgrade_type === "upgrade") {
			skills_min_score[upgrade_name][upgrade_progress] = step_count+1;
		}

		step_count++;
	}
}

let bonus_min_score = {};
for (const upgrade of upgrades) {
	const upgrade_name = upgrade.name;
	bonus_min_score[upgrade_name] = {};

	let step_count = 0;
	for (const step of upgrade.steps) {
		const upgrade_type = step.type;
		const upgrade_progress = step.progress;
		
		if (upgrade_type === "bonus") {
			bonus_min_score[upgrade_name][upgrade_progress] = step_count+1;
		}

		step_count++;
	}
}

//Debug minimum score for skills
// for (const skill in skills_min_score) {
// 	console.warn(`Skill: ${skill}`);
// 	const skillDetails = skills_min_score[skill];
// 	for (const key in skillDetails) {
// 		const value = skillDetails[key];
// 		console.warn(`   ${key}: ${value}`);
// 	}
// }

//Debug minimum score for skills
// for (const skill in bonus_min_score) {
// 	console.warn(`Skill: ${skill}`);
// 	const skillDetails = bonus_min_score[skill];
// 	for (const key in skillDetails) {
// 		const value = skillDetails[key];
// 		console.warn(`   ${key}: ${value}`);
// 	}
// }

// ICONS
const icons = {
	speed_upgrade: "textures/ui/speed_effect",
	speed_research: "textures/ui/speed_effect",
	speed_max: "textures/ui/speed_effect",

	resistance_upgrade: "textures/ui/resistance_effect",
	resistance_research: "textures/ui/resistance_effect",
	resistance_max: "textures/ui/resistance_effect",

	jump_boost_upgrade: "textures/ui/jump_boost_effect",
	jump_boost_research: "textures/ui/jump_boost_effect",
	jump_boost_max: "textures/ui/jump_boost_effect",

	haste_upgrade: "textures/ui/haste_effect",
	haste_research: "textures/ui/haste_effect",
	haste_max: "textures/ui/haste_effect",

	strength_upgrade: "textures/ui/strength_effect",
	strength_research: "textures/ui/strength_effect",
	strength_max: "textures/ui/strength_effect",

	luck_upgrade: "textures/oct/plev/ui/luck_effect",
	luck_research: "textures/oct/plev/ui/luck_effect",
	luck_max: "textures/oct/plev/ui/luck_effect"
}

// OPEN UI
system.afterEvents.scriptEventReceive.subscribe(({id, sourceEntity}) => {
	if (sourceEntity === undefined || sourceEntity?.typeId !== "minecraft:player") return;
	if (id === "oct_plev:skill_tree") skill_tree(sourceEntity);
})

// UI
function skill_tree(player) {
	player.runCommand("/function oct/plev/skill_tree/init_player");

	var level = player.level;
	let skill_tree = new ActionFormData()

	.title({translate: "ui.oct_plev.skill_tree.title"})
	.body(
		{
			translate: `%ui.oct_plev.skill_tree.body\n%ui.oct_plev.skill_tree.current_level ${level}\n\n`
		}
	)

	// UPGRADES
	for (const upgrade of upgrades) {
		const upgrade_name = upgrade.name;
		const upgrade_score = getUpgradeScore(player, upgrade_name);

		// FULLY UPGRADED BUTTON
		if (upgrade_score >= upgrade.steps.length)
		{
			var icon = icons[`${upgrade_name}_max`];
			skill_tree.button({translate: `%ui.oct_plev.skill_tree.${upgrade_name}.max`}, icon);
			continue;
		}

		const step = upgrade.steps[upgrade_score];
		const upgrade_type = step.type;
		const upgrade_progress = step.progress;
		const upgrade_cost = step.cost;
		let cost_color = "";

		// Color of cost text when player don't have enough xp
		if (level < upgrade_cost) {
			cost_color = "§c"
		}

		// RESEARCH BUTTON
		if (upgrade_type === "research")
		{
			let research_progress =
				upgrade_progress <= 3 ? 0 : 
				upgrade_progress <= 6 ? 1 :
				upgrade_progress <= 9 ? 2 : 0;
			
			var icon = icons[`${upgrade_name}_research`];
			skill_tree.button({translate: `%ui.oct_plev.skill_tree.${upgrade_name}.research.${research_progress} %ui.oct_plev.skill_tree.research.${upgrade_progress}\n%ui.oct_plev.skill_tree.cost ${cost_color}${upgrade_cost} %ui.oct_plev.skill_tree.cost.lvl`}, icon);
		}
		else
		// UPGRADE / BONUS BUTTON
		{
			var icon = icons[`${upgrade_name}_upgrade`];
			skill_tree.button({translate: `%ui.oct_plev.skill_tree.${upgrade_name}.${upgrade_type}.${upgrade_progress}\n%ui.oct_plev.skill_tree.cost ${cost_color}${upgrade_cost} %ui.oct_plev.skill_tree.cost.lvl`}, icon);
		}
	}

	// CLICKING ON BUTTONS
	skill_tree.show(player).then((r) => {
		if (r.selection !== undefined) {
			const upgrade = upgrades[r.selection];
			const upgrade_name = upgrade.name;
			const upgrade_score = getUpgradeScore(player, upgrade_name);

			if (upgrade_score < upgrades[r.selection].steps.length) 
			{
				const step = upgrade.steps[upgrade_score];
				const upgrade_type = step.type;
				const upgrade_cost = step.cost;

				// Research
				if (upgrade_type === "research") 
				{
					if (level >= upgrade_cost)
					{
						// research successful
						player.runCommand("/function oct/plev/skill_tree/research_effect");
						addUpgradeScore(player, upgrade_name);
						player.runCommand(`/xp -${upgrade_cost}L @s`);
					}
					else
					{
						// research fail
						player.runCommand("/function oct/plev/skill_tree/research_fail_effect");
					}
				}
				// Upgrade
				if (upgrade_type === "upgrade" || upgrade_type === "bonus" ) 
					{
						if (level >= upgrade_cost)
						{
							// upgrade successful
							giveEffects(player);
							player.runCommand("/function oct/plev/skill_tree/upgrade_effect");
							addUpgradeScore(player, upgrade_name);
							player.runCommand(`/xp -${upgrade_cost}L @s`);
						}
						else
						{
							// upgrade fail
							player.runCommand("/function oct/plev/skill_tree/upgrade_fail_effect");
						}
					}
			}
			else 
			{
				//MAX UPGRADE
				player.runCommand("/function oct/plev/skill_tree/fully_upgraded_effect");
			}
		}
	});
}

function getUpgradeScore(player, upgrade) {
	let scoreboard_name = "oct_plev_skill_" + upgrade;
	let scoreboard = world.scoreboard.getObjective(scoreboard_name);
	if (scoreboard === undefined) {
		world.scoreboard.addObjective(scoreboard_name);
		scoreboard = world.scoreboard.getObjective(scoreboard_name);
	}

	try {
		return world.scoreboard.getObjective(scoreboard_name).getScore(player);
	} catch {
		return 0
	}
}

function addUpgradeScore(player, upgrade) {
	let scoreboard_name = "oct_plev_skill_" + upgrade;
	player.runCommand(`scoreboard players add @s ${scoreboard_name} 1`);
}



// EFFECTS

world.afterEvents.playerSpawn.subscribe((event) => {
	// Init
	giveEffects(event.player)
});

function giveEffects(player) {
	for (const upgrade of upgrades) {
		const upgrade_name = upgrade.name;

		const upgrade_score = getUpgradeScore(player, upgrade_name);

		for (const amplifier in skills_min_score[upgrade_name]) {
			const skill_cost = skills_min_score[upgrade_name][amplifier]

			if (upgrade_score >= skill_cost) {
				if (upgrade_name === "luck") {
					player.runCommand(`/scoreboard players set @s oct_plev_skill_luck_u ${amplifier}`);
				}
				else {
					player.runCommand(`/effect @s ${upgrade_name} 10000000 ${amplifier} true`);
				}
			}
		}
	}
}

// ATTACK EFFECTS
world.afterEvents.entityHitEntity.subscribe(data => {
	const player = data.damagingEntity;
	const target = data.hitEntity;
	if (player.typeId === undefined) return;

	if (player.typeId === 'minecraft:player' && target.isValid())
	{
		for (const upgrade of upgrades) {
			const upgrade_name = upgrade.name;
			const upgrade_score = getUpgradeScore(player, upgrade_name);
	
			for (const amplifier in bonus_min_score[upgrade_name]) {
				const skill_cost = bonus_min_score[upgrade_name][amplifier];
	
				if (upgrade_score >= skill_cost) {
					const effect_amplifier = parseInt(amplifier);
					const effect_duration = (effect_amplifier+1) * 20;

					if (upgrade.bonus === "fire_aspect")
					{
						target.setOnFire(effect_duration/20 +1, true)
					}
					else if (upgrade.bonus === "saturation") {
						player.runCommand(`/effect @s ${upgrade.bonus} ${effect_duration/20} ${effect_amplifier}`)
					}
					else {
						// apply bonus effect to attack target
						target.addEffect(upgrade.bonus, effect_duration, {amplifier: effect_amplifier});
					}
				}
			}
		}
	}
});

// LUCK EFFECT
const oreBlocks = {
	"minecraft:iron_ore": "minecraft:raw_iron",
	"minecraft:deepslate_iron_ore": "minecraft:raw_iron",

	"minecraft:gold_ore": "minecraft:raw_gold",
	"minecraft:deepslate_gold_ore": "minecraft:raw_gold",

	"minecraft:copper_ore": "minecraft:raw_copper",
	"minecraft:deepslate_copper_ore": "minecraft:raw_copper",

	"minecraft:emerald_ore": "minecraft:emerald",
	"minecraft:deepslate_emerald_ore": "minecraft:emerald",

	"minecraft:diamond_ore": "minecraft:diamond",
	"minecraft:deepslate_diamond_ore": "minecraft:diamond",

	"minecraft:lapis_ore": "minecraft:lapis_lazuli",
	"minecraft:deepslate_lapis_ore": "minecraft:lapis_lazuli",

	"minecraft:redstone_ore": "minecraft:redstone",
	"minecraft:deepslate_redstone_ore": "minecraft:redstone",

	"minecraft:coal_ore": "minecraft:coal",
	"minecraft:deepslate_coal_ore": "minecraft:coal",

	"minecraft:nether_gold_ore": "minecraft:gold_nugget",

	"minecraft:quartz_ore": "minecraft:quartz",
};

world.beforeEvents.playerBreakBlock.subscribe(data => {
	const player = data.player;
	const block = data.block;
	const tool = data.itemStack;

	if (player.getGameMode() === "creative" ||tool === undefined || !tool.typeId.includes("pickaxe")) return;

	const amplifier = getLuckScore(player);
	const random = getRandomInt(1, 10);

	// 10%, 20%, 30%
	if (amplifier >= 0 && random <= (amplifier+1)) {
		if (oreBlocks[block.typeId]) {
			const location = {
				x: block.x,
				y: block.y,
				z: block.z
			}

			const item_id = oreBlocks[block.typeId];
			const item = new ItemStack(item_id, amplifier+1);
			system.run(() => {
				block.dimension.spawnItem(item, location);
				player.runCommand(`/execute positioned ${block.x} ${block.y} ${block.z} run function oct/plev/skill_tree/mining_luck_drop`)
			});
		}
	}
});

function getLuckScore(player) {
	try {
		return world.scoreboard.getObjective("oct_plev_skill_luck_u").getScore(player);
	} catch {
		return -1;
	}
}
function getRandomInt(min, max) {
	min = Math.ceil(min);
	max = Math.floor(max);
	return Math.floor(Math.random() * (max - min + 1)) + min;
}



// MAIN
function main() {
	for (let player of world.getAllPlayers()) {
		giveEffects(player);
	}
}

system.runInterval(main, 100);