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

export class McfWashingMachine {
	static getWashData(entity) {
		return {
			soapProgress: entity.getDynamicProperty("mr:wash_soap_progress") ?? 0,
			soapValue: entity.getDynamicProperty("mr:wash_soap_value") ?? 0,
			soapTick: entity.getDynamicProperty("mr:wash_soap_tick") ?? 0,
			bubbles: entity.getDynamicProperty("mr:wash_bubbles") ?? 0
		};
	}
	static setWashData(entity, data) {
		entity.setDynamicProperty("mr:wash_soap_progress", data.soapProgress);
		entity.setDynamicProperty("mr:wash_soap_value", data.soapValue);
		entity.setDynamicProperty("mr:wash_soap_tick", data.soapTick);
		entity.setDynamicProperty("mr:wash_bubbles", data.bubbles);
	}
	static validateArmorSlots(inventory, entity) {
		const checks = [
			{ slot: 1, keyword: "helmet" },
			{ slot: 2, keyword: "chestplate" },
			{ slot: 3, keyword: "leggings" },
			{ slot: 4, keyword: "boots" }
		];
		for (const { slot, keyword } of checks) {
			const item = inventory.getItem(slot);
			if (item && !item.typeId.includes(keyword)) {
				entity.dimension.spawnItem(item, entity.location);
				inventory.setItem(slot, undefined);
			}
		}
	}
	static needsWashing(armors) {
		return armors.some(item => {
			if (!item) return false;
			const durability = item.getComponent("durability");
			return durability && durability.damage > 0;
		});
	}
	static getArmors(inventory) {
		return [
			inventory.getItem(1),
			inventory.getItem(2),
			inventory.getItem(3),
			inventory.getItem(4)
		];
	}
	static setupSoapTimer(inventory, soap, washData) {
		if (soap.typeId === "mr:soap_water") {
			inventory.setItem(5, new ItemStack("mr:timer", 64));
			washData.soapValue = 30;
		} else if (soap.typeId === "mr:super_soap_water") {
			inventory.setItem(6, new ItemStack("mr:timer", 64));
			washData.soapValue = 10;
		}
		washData.soapProgress = 2500;
	}
	static updateTimers(inventory, washData) {
		const timerSlot = (washData.soapValue === 30 ? 5 : 6);
		const valueSoap = Math.max(1, Math.ceil((washData.soapProgress / 2500) * 64));
		const valueBubbles = Math.max(1, Math.ceil((washData.soapTick / washData.soapValue) * 64));
		
		inventory.setItem(timerSlot, new ItemStack("mr:timer", valueSoap));
		inventory.setItem(7, new ItemStack("mr:timer", valueBubbles));
	}
	static repairArmors(armors, inventory) {
		armors.forEach((item, i) => {
			if (!item) return;
			const durability = item.getComponent("durability");
			if (durability?.damage > 0) {
				durability.damage = Math.min(durability.damage - 1, durability.maxDurability);
				inventory.setItem(i + 1, item);
			}
		});
	}
	static stopWashing(entity, inventory, washData) {
        washData.bubbles = 0;
        inventory.setItem(7, new ItemStack("mr:timer", 1));
        this.setWashData(entity, washData);
        entity.triggerEvent("mr:stop");
    }
	static resetSoapValues(entity, inventory, washData) {
        washData.bubbles = 0;
		washData.soapTick = 0;
		washData.soapValue = 0;
        inventory.setItem(5, new ItemStack("mr:timer", 1));
        inventory.setItem(6, new ItemStack("mr:timer", 1));
        inventory.setItem(7, new ItemStack("mr:timer", 1));
        this.setWashData(entity, washData);
        entity.triggerEvent("mr:stop");
    }
	static handleCheckEvent(entity, inventory, washData) {
		this.validateArmorSlots(inventory, entity);
		const soap = inventory.getItem(0);
		const armors = this.getArmors(inventory);
		const needsWash = this.needsWashing(armors);
		if (soap?.hasTag("mc:is_soap") && washData.soapProgress <= 0 && needsWash) {
			this.setupSoapTimer(inventory, soap, washData);
			decrementItemInInventory(entity, 0, { convertTo: new ItemStack("minecraft:bucket", 1) });
		}
		if (washData.soapProgress > 0 && needsWash) {
			this.setWashData(entity, washData);
			entity.triggerEvent("mr:start");
			return;
		}
		this.setWashData(entity, washData);
	}
	static handleUpdateTimerEvent(entity, inventory, washData) {
		this.validateArmorSlots(inventory, entity);
		const armors = this.getArmors(inventory);
		const needsWash = this.needsWashing(armors);
		if (!needsWash) return this.stopWashing(entity, inventory, washData);
		if (washData.soapProgress <= 0) return this.resetSoapValues(entity, inventory, washData);
		washData.soapProgress--;
		washData.soapTick++;
		if (washData.soapTick >= washData.soapValue) {
			washData.soapTick = 0;
			this.repairArmors(armors, inventory);
		}
		this.updateTimers(inventory, washData);
		this.setWashData(entity, washData);
	}
	static registerEvent() {
		world.afterEvents.dataDrivenEntityTrigger.subscribe(({ entity, eventId }) => {
			if (!entity?.isValid) return;
			const inventory = entity.getComponent("inventory").container;
			const washData = this.getWashData(entity);
			if (eventId === "mr:check") this.handleCheckEvent(entity, inventory, washData);
			if (eventId === "mr:update_timer") this.handleUpdateTimerEvent(entity, inventory, washData);
		}, {
			entityTypes: ["mr:washing_machine"],
			eventTypes: ["mr:check", "mr:update_timer"]
		})
	}
}