import { ItemStack, world } from '@minecraft/server';
import { addItemInInventory, decrementItemInInventory } from '../util/utils';
import { FREEZE_DURATION, FREEZING_RECIPES } from './Recipes';

export class McfFreezer {
	static getFreezerData(entity) {
		return {
			coolingCharge: entity.getDynamicProperty("mr:cooling_charge") ?? 0,
			coolingTotal: entity.getDynamicProperty("mr:cooling_total") ?? 1,
			freezeProgress: entity.getDynamicProperty("mr:freeze_progress") ?? 0,
			freezeTotal: entity.getDynamicProperty("mr:freeze_total") ?? 1,
			lastItem: entity.getDynamicProperty("mr:last_item") ?? ""
		};
	}
	static setFreezerData(entity, data) {
		entity.setDynamicProperty("mr:cooling_charge", data.coolingCharge);
		entity.setDynamicProperty("mr:cooling_total", data.coolingTotal);
		entity.setDynamicProperty("mr:freeze_progress", data.freezeProgress);
		entity.setDynamicProperty("mr:freeze_total", data.freezeTotal);
		entity.setDynamicProperty("mr:last_item", data.lastItem);
	}
	static canStackItem(outputSlot, resultItemId) {
		if (!outputSlot) return true;
		if (outputSlot.typeId !== resultItemId) return false;
		return outputSlot.amount < outputSlot.maxAmount;
	}
	static stopFreezing(entity, inventory, freezeData) {
		freezeData.freezeProgress = 0;
		freezeData.freezeTotal = 1;
		freezeData.lastItem = "";
		inventory.setItem(4, new ItemStack("mr:timer", 1));
		inventory.setItem(5, new ItemStack("mr:timer", 1));
		this.setFreezerData(entity, freezeData);
		entity.triggerEvent("mr:stop");
	}
	static updateVisuals(inventory, freezeData) {
		const coolingVisual = Math.max(1, Math.ceil((freezeData.coolingCharge / freezeData.coolingTotal) * 64));
		inventory.setItem(3, new ItemStack("mr:timer", coolingVisual));
		const progressVisual = Math.max(1, Math.ceil((freezeData.freezeProgress / freezeData.freezeTotal) * 64));
		inventory.setItem(4, new ItemStack("mr:timer", progressVisual));
	}
	static completeFreezing(entity, inventory, freezeData, recipe) {
		freezeData.freezeProgress = 0;
		decrementItemInInventory(entity, 1, { convertTo: recipe.convertTo ? new ItemStack(recipe.convertTo, 1) : undefined });
		addItemInInventory(inventory, 2, new ItemStack(recipe.freezing, 1));
		const inputItem = inventory.getItem(1);
		const outputSlot = inventory.getItem(2);
		if (!inputItem || !FREEZING_RECIPES[inputItem.typeId] || !this.canStackItem(outputSlot, recipe.freezing)) 
			this.stopFreezing(entity, inventory, freezeData);
	}
	static handleCheckEvent(entity, inventory, freezeData) {
		const coolingItem = inventory.getItem(0);
		const inputItem = inventory.getItem(1);
		const outputSlot = inventory.getItem(2);
		
		if (!inputItem) return;
		const recipe = FREEZING_RECIPES[inputItem.typeId];
		if (!recipe) return;
		if (!this.canStackItem(outputSlot, recipe.freezing)) return;

		if (freezeData.coolingCharge <= 0) {
			if (!coolingItem) return;
			const coolingDuration = FREEZE_DURATION[coolingItem.typeId];
			if (!coolingDuration) return;
			freezeData.coolingCharge = coolingDuration;
			freezeData.coolingTotal = coolingDuration;
			decrementItemInInventory(entity, 0);
		}
		freezeData.freezeProgress = 0;
		freezeData.freezeTotal = 100;
		freezeData.lastItem = inputItem.typeId;
		this.setFreezerData(entity, freezeData);
		entity.triggerEvent("mr:start");
	}
	static handleUpdateTimerEvent(entity, inventory, freezeData) {
		const coolingItem = inventory.getItem(0);
		const inputItem = inventory.getItem(1);
		const outputSlot = inventory.getItem(2);
		if (!inputItem || inputItem.typeId !== freezeData.lastItem)
			return this.stopFreezing(entity, inventory, freezeData);
		const recipe = FREEZING_RECIPES[inputItem.typeId];
		if (!recipe || !this.canStackItem(outputSlot, recipe.freezing))
			return this.stopFreezing(entity, inventory, freezeData);
		if (freezeData.coolingCharge <= 0) {
			if (coolingItem && FREEZE_DURATION[coolingItem.typeId]) {
				const coolingDuration = FREEZE_DURATION[coolingItem.typeId];
				freezeData.coolingCharge = coolingDuration;
				freezeData.coolingTotal = coolingDuration;
				decrementItemInInventory(entity, 0);
			} else return this.stopFreezing(entity, inventory, freezeData);
		}
		freezeData.coolingCharge--;
		freezeData.freezeProgress++;
		if (freezeData.freezeProgress >= freezeData.freezeTotal) 
			this.completeFreezing(entity, inventory, freezeData, recipe);
		this.updateVisuals(inventory, freezeData);
		this.setFreezerData(entity, freezeData);
	}
	static registerEvent() {
		world.afterEvents.dataDrivenEntityTrigger.subscribe(({ entity, eventId }) => {
			if (!entity?.isValid) return;
			const inventory = entity.getComponent("inventory").container;
			const freezerData = this.getFreezerData(entity);
			if (eventId === "mr:check") this.handleCheckEvent(entity, inventory, freezerData);
			if (eventId === "mr:update_timer") this.handleUpdateTimerEvent(entity, inventory, freezerData);
		}, {
			entityTypes: ["mr:freezer"],
			eventTypes: ["mr:check", "mr:update_timer"]
		})
	}
}