import { system, world, ItemLockMode } from "@minecraft/server";

const CONTAINER_TYPE = {
	"mr:present_white": { event: "mcf:present", nameTag: "MrCrayFish.present.white" },
	"mr:present_light_gray": { event: "mcf:present", nameTag: "MrCrayFish.present.light_gray" },
	"mr:present_gray": { event: "mcf:present", nameTag: "MrCrayFish.present.gray" },
	"mr:present_black": { event: "mcf:present", nameTag: "MrCrayFish.present.black" },
	"mr:present_brown": { event: "mcf:present", nameTag: "MrCrayFish.present.brown" },
	"mr:present_red": { event: "mcf:present", nameTag: "MrCrayFish.present.red" },
	"mr:present_orange": { event: "mcf:present", nameTag: "MrCrayFish.present.orange" },
	"mr:present_yellow": { event: "mcf:present", nameTag: "MrCrayFish.present.yellow" },
	"mr:present_lime": { event: "mcf:present", nameTag: "MrCrayFish.present.lime" },
	"mr:present_green": { event: "mcf:present", nameTag: "MrCrayFish.present.green" },
	"mr:present_cyan": { event: "mcf:present", nameTag: "MrCrayFish.present.cyan" },
	"mr:present_light_blue": { event: "mcf:present", nameTag: "MrCrayFish.present.light_blue" },
	"mr:present_blue": { event: "mcf:present", nameTag: "MrCrayFish.present.blue" },
	"mr:present_purple": { event: "mcf:present", nameTag: "MrCrayFish.present.purple" },
	"mr:present_magenta": { event: "mcf:present", nameTag: "MrCrayFish.present.magenta" },
	"mr:present_pink": { event: "mcf:present", nameTag: "MrCrayFish.present.pink" },
	"mr:package": { event: "mcf:package", nameTag: "MrCrayFish.package" },
	"mr:envelope": { event: "mcf:envelope", nameTag: "MrCrayFish.envelope" },
}
class McfContainer {
	static processContainer(ent, containerId, containerCache) {
		if (!ent.isValid) {
			containerCache.delete(containerId);
			return;
		}
		const ownerId = ent.getDynamicProperty("mcf:owner_id");
		if (!ownerId) {
			ent.remove();
			containerCache.delete(containerId);
			return;
		}
		const owner = world.getEntity(ownerId);
		if (!owner?.isValid) {
			ent.remove();
			containerCache.delete(containerId);
			return;
		}
		const currentContainer = owner.getDynamicProperty("mcf:current");
		const enId = ent.getDynamicProperty("mcf:container_id");
		
		if (currentContainer !== enId || owner.isSneaking) this.saveAndRemoveContainer(ent, enId, containerCache);
		else this.followOwner(ent, owner);
	}
	static saveAndRemoveContainer(ent, containerId, containerCache) {
		try {
			const structName = `mcf:container_${containerId}`;
			const existingStructure = world.structureManager.get(structName);
			if (existingStructure) world.structureManager.delete(structName);
			const structure = world.structureManager.createFromWorld(structName, ent.dimension, ent.location, ent.location,
				{ includeBlocks: false, includeEntities: true, saveMode: "World" }
			);
			structure.saveToWorld();
		} catch (e) {}
		finally {
			ent.remove();
			containerCache.delete(containerId);
		}
	}
	static followOwner(ent, owner) {
		const headLoc = owner.getHeadLocation();
		ent.teleport(headLoc, { dimension: owner.dimension, keepVelocity: true });
		ent.setProperty("mcf:despawn_timer", 0);
	}
}
class McfPlayer {
	static processPlayer(player, containerCache) {
		const inventory = player.getComponent("inventory")?.container;
		const mainhand = inventory.getItem(player.selectedSlotIndex);
		this.processHotbarItems(player, inventory);
		if (mainhand?.hasTag("mcf:is_container")) this.handleContainerInHand(player, mainhand, inventory, containerCache);
		else this.handleNoContainerInHand(player);
	}
	static processHotbarItems(player, inventory) {
		if (!inventory) return;
		for (let i = 0; i < 9; i++) {
			const temp = inventory.getItem(i);
			if (!temp?.hasTag("mcf:is_container")) continue;
			temp.lockMode = (i === player.selectedSlotIndex && !player.isSneaking) ? ItemLockMode.slot : ItemLockMode.none;
			inventory.setItem(i, temp);
		}
	}
	static handleContainerInHand(player, mainhand, inventory, containerCache) {
		let id = mainhand.getDynamicProperty("mcf:container_id");
		const currentContainer = player.getDynamicProperty("mcf:current");
		if (!id) this.createNewContainer(player, mainhand, inventory, containerCache);
		else if (id && currentContainer === "") this.loadExistingContainer(player, mainhand, inventory, id, containerCache);
		else if (id && currentContainer !== id) this.switchContainer(player, currentContainer);
	}
	static createNewContainer(player, mainhand, inventory, containerCache) {
		const containerEnt = player.dimension.spawnEntity("mcf:dynamic_container", player.getHeadLocation());
		const id = containerEnt.id;
		
		const data = CONTAINER_TYPE[mainhand?.typeId];
		if (!data) return;
		containerEnt.setDynamicProperty("mcf:owner_id", player.id);
		containerEnt.setDynamicProperty("mcf:container_id", id);
		containerEnt.nameTag = data.nameTag;
		containerEnt.triggerEvent(data.event);
		player.setDynamicProperty("mcf:current", id);
		containerCache.set(id, containerEnt);
		
		const mainhandReplace = mainhand.clone();
		mainhandReplace.setDynamicProperty("mcf:container_id", id);
		mainhandReplace.setDynamicProperty("mcf:owner_id", player.id);
		mainhandReplace.lockMode = ItemLockMode.slot;
		inventory.setItem(player.selectedSlotIndex, mainhandReplace);
	}
	static loadExistingContainer(player, mainhand, inventory, id, containerCache) {
		try {
			const structName = `mcf:container_${id}`;
			const containerData = world.structureManager.get(structName);
			if (!containerData) return;

			world.structureManager.place(containerData, player.dimension, player.getHeadLocation(), { includeBlocks: false, includeEntities: true });
			let spawnedEntity = containerCache.get(id);
			if (!spawnedEntity) {
				const nearbyEntities = player.dimension.getEntities({
					location: player.getHeadLocation(),
					maxDistance: 2,
					type: "mcf:dynamic_container"
				});
				spawnedEntity = nearbyEntities.find(ent => ent.getDynamicProperty("mcf:container_id") === id);
				if (spawnedEntity) {
					containerCache.set(id, spawnedEntity);
				}
			}
			if (spawnedEntity) {
				spawnedEntity.setDynamicProperty("mcf:owner_id", player.id);
				player.setDynamicProperty("mcf:current", id);
				mainhand.lockMode = ItemLockMode.slot;
				inventory.setItem(player.selectedSlotIndex, mainhand);
			}
		} catch (e) {}
	}
	static switchContainer(player, currentContainer) {
		player.setDynamicProperty("mcf:last", currentContainer);
		player.setDynamicProperty("mcf:current", "");
	}
	static handleNoContainerInHand(player) {
		const currentContainer = player.getDynamicProperty("mcf:current");
		if (currentContainer) {
			player.setDynamicProperty("mcf:last", currentContainer);
			player.setDynamicProperty("mcf:current", "");
		}
	}
}
export class McfContainerManager {
	static CONTAINER_CACHE = new Map();
	static INTERVAL_ID = null;

	static init() {
		if (this.INTERVAL_ID !== null) {
			this.clearInterval();
		}
		this.INTERVAL_ID = system.runInterval(() => {
			this.runContainerTick();
		});
	}
	static clearInterval() {
        if (this.INTERVAL_ID !== null) {
            system.clearRun(this.INTERVAL_ID);
            this.INTERVAL_ID = null;
        }
    }
	static runContainerTick() {
		this.updateContainerCache();
		this.processPlayers();
		this.processContainers();
	}
	static updateContainerCache() {
		this.CONTAINER_CACHE.clear();
		const players = world.getAllPlayers();
		const dimensions = new Set();
		for (const player of players) {
			dimensions.add(player.dimension);
		}
		for (const dim of dimensions) {
			const entities = dim.getEntities({ type: "mcf:dynamic_container" });
			for (const ent of entities) {
				if (ent.isValid) {
					const containerId = ent.getDynamicProperty("mcf:container_id");
					if (containerId) {
						this.CONTAINER_CACHE.set(containerId, ent);
					}
				}
			}
		}
	}
	static processPlayers() {
		for (const player of world.getAllPlayers()) {
			McfPlayer.processPlayer(player, this.CONTAINER_CACHE);
		}
	}
	static processContainers() {
		for (const [containerId, ent] of this.CONTAINER_CACHE.entries()) {
			McfContainer.processContainer(ent, containerId, this.CONTAINER_CACHE);
		}
	}
}