import { decrementItemInHand, spawnEntityRotatedByBlock } from '../util/utils';
import { directionState } from '../util/globalVariables';
import { ItemStack } from '@minecraft/server';

const BLENDER_RECIPES = {
	fruit_crush: {
		ingredients: [
			{ id: "minecraft:apple", amount: 2 },
			{ id: "minecraft:melon_slice", amount: 4 }
		]
	},
	veggie_juice: {
		ingredients: [
			{ id: "minecraft:carrot", amount: 4 },
			{ id: "minecraft:potato", amount: 1 },
			{ id: "minecraft:pumpkin_pie", amount: 2 }
		]
	},
	cookies_cream: {
		ingredients: [
			{ id: "minecraft:cookie", amount: 2 },
			{ id: "minecraft:milk_bucket", amount: 1 }
		]
	},
	energy_drink: {
		ingredients: [
			{ id: "minecraft:redstone", amount: 8 },
			{ id: "minecraft:fire_charge", amount: 1 },
			{ id: "minecraft:sugar", amount: 16 }
		]
	},
	egg_nog: {
		ingredients: [
			{ id: "minecraft:egg", amount: 4 },
			{ id: "minecraft:sugar", amount: 2 },
			{ id: "minecraft:milk_bucket", amount: 1 }
		]
	}
};
export class McfBlender {
	constructor() {
		this.onPlayerInteract = this.onPlayerInteract.bind(this);
	}
	onPlayerInteract(e) {
		const { player, block, dimension } = e;
		const item = player.getComponent("inventory").container.getItem(player.selectedSlotIndex);
		const blender = dimension.getEntitiesAtBlockLocation(block.location).find(en => en.typeId === "mr:blender_food");
		
		if (blender?.getProperty("mcf:powered"))
			return player.onScreenDisplay.setActionBar({ translate: "mcf.blender.already_working" });
		if (blender?.getProperty("mcf:amount") > 0 && item?.typeId !== "mr:cup")
			return player.onScreenDisplay.setActionBar({ translate: "mcf.blender.use_cup" });
		if (this.tryServeDrink(blender, player, dimension, item)) return;
		if (this.tryStartNewRecipe(blender, player, block, item)) return;
		this.tryContinueRecipe(blender, player, dimension, item);
	}
	tryServeDrink(blender, player, dimension, item) {
		if (!blender || item?.typeId !== "mr:cup") return false;
		const currentAmount = blender.getProperty("mcf:amount");
		if (currentAmount <= 0) {
			if (blender.getProperty("mcf:item_step") === 0) blender.remove();
			return true;
		}
		const recipeName = blender.getProperty("mcf:recipe");
		decrementItemInHand(player, false);
		dimension.spawnItem(new ItemStack(`mr:cup_${recipeName}`, 1), player.location);
		const newAmount = currentAmount - 1;
		blender.setProperty("mcf:amount", newAmount);
		if (newAmount === 0) {
			blender.remove();
			player.onScreenDisplay.setActionBar({ translate: "mcf.blender.last_serving" });
		} else {
			player.onScreenDisplay.setActionBar({ translate: "mcf.blender.serving_taken", with: [ `${newAmount}` ] });
		}
		dimension.playSound("bottle.dragonbreath", player.location);
		dimension.playSound("bucket.fill_water", player.location);
		return true;
	}
	tryStartNewRecipe(blender, player, block, item) {
		if (blender || !item) return false;
		const recipeEntry = Object.entries(BLENDER_RECIPES).find(([_, data]) => data.ingredients[0].id === item.typeId);
		if (!recipeEntry) return false;
		const [name, recipe] = recipeEntry;
		const firstIngredient = recipe.ingredients[0];
		if (item.amount < firstIngredient.amount) {
			player.onScreenDisplay.setActionBar({ translate: "%%1%%2", with: { rawtext: [ { translate: "mcf.blender.need_ingredient", with: [ `${firstIngredient.amount}` ] }, { translate: `item.mcf.${firstIngredient.id}` } ] } });
			return true;
		}
		this.createBlender(player, block, name, firstIngredient);
		return true;
	}
	tryContinueRecipe(blender, player, dimension, item) {
		if (!blender) return;
		const recipeName = blender.getProperty("mcf:recipe");
		const step = blender.getProperty("mcf:item_step");
		const recipe = BLENDER_RECIPES[recipeName];
		if (!recipe) return blender.remove();
		const nextIngredient = recipe.ingredients[step];
		if (!nextIngredient) {
			this.handleCompleteRecipe(blender, player, dimension, step);
			return;
		}
		this.handleNextIngredient(blender, player, dimension, item, recipe, step, nextIngredient, recipeName);
	}
	handleCompleteRecipe(blender, player, dimension, step) {
		if (player.isSneaking) {
			blender.setProperty("mcf:powered", true);
			dimension.playSound("random.lever_click", blender.location, { pitch: 0.6 });
		} else if (step > 0)
			this.rollbackStep(blender, player, dimension, step - 1);
	}
	handleNextIngredient(blender, player, dimension, item, recipe, step, nextIngredient, recipeName) {
		if (item?.typeId !== nextIngredient.id) {
			this.handleWrongIngredient(blender, player, dimension, step);
			return;
		}
		if (item.amount < nextIngredient.amount) {
			player.onScreenDisplay.setActionBar({ translate: "%%1%%2", with: { rawtext: [ { translate: "mcf.blender.need_ingredient", with: [ `${nextIngredient.amount}` ] }, { translate: `item.mcf.${nextIngredient.id}` } ] } });
			return;
		}
		this.addIngredient(blender, player, nextIngredient, step);
		const isComplete = step + 1 >= recipe.ingredients.length;
		if (isComplete) player.onScreenDisplay.setActionBar({ translate: "%%1%%2%%3", with: { rawtext: [ { translate: "mcf.blender.set_recipe_0" }, { translate: `item.mr:cup_${recipeName}` }, { translate: "mcf.blender.set_recipe_1" } ] } });
		else {
			player.onScreenDisplay.setActionBar({ translate: "mcf.blender.add_ingredient_step", with: [ `${step + 1}`, `${recipe.ingredients.length}` ] });
		}
		dimension.playSound("block.itemframe.add_item", blender.location);
	}
	handleWrongIngredient(blender, player, dimension, step) {
		if (step > 0) this.rollbackStep(blender, player, dimension, step - 1);
		else blender.remove();
	}
	rollbackStep(blender, player, dimension, targetStep) {
		const invBlender = blender.getComponent("inventory").container;
		const currentStep = blender.getProperty("mcf:item_step");
		const item = invBlender.getItem(currentStep - 1);
		if (item) {
			dimension.spawnItem(item, player.location);
			invBlender.setItem(currentStep - 1, undefined);
		}
		blender.setProperty("mcf:item_step", targetStep);
		if (targetStep === 0 && !invBlender.getItem(0)) {
			blender.remove();
		}
	}
	addIngredient(blender, player, ingredient, step) {
		blender.getComponent("inventory").container.setItem(step, new ItemStack(ingredient.id, ingredient.amount));
		decrementItemInHand(player, false, ingredient.amount);
		blender.setProperty("mcf:item_step", step + 1);
	}
	createBlender(player, block, recipeName, firstIngredient) {
		const direction = block.permutation.getState(directionState);
		const blender = spawnEntityRotatedByBlock("mr:blender_food", block, direction, { init: block.bottomCenter() });
		blender.triggerEvent(`mcf:${recipeName}`);
		blender.setProperty("mcf:recipe", recipeName);
		player.dimension.playSound("block.itemframe.add_item", block.center());
		this.addIngredient(blender, player, firstIngredient, 0);
	}
}