// File for handling the spawning of seahorses from buckets,
// to make sure the spawned seahorse is identical

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



// bucketing is done as an AFTER event, so that the data is saved to the new bucket item
world.afterEvents.playerInteractWithEntity.subscribe((eventData) => {
    const { player, target, itemStack } = eventData;

	// first and foremost, make sure the player is interacting with a seahorse
	if (target.typeId != "cyn_hao:seahorse_small") {
		return;
	}

	// make sure to only save the seahorse's properties if the player used a water bucket on a seahorse
	if ((itemStack != undefined) && (itemStack.typeId === "cyn_hao:seahorse_bucket")) {

		// save the seahorse's color and scale properties and if they are a baby to the item
		// properties are stored on the item, so that the bucket is guarenteed to spawn the right seahorse
		// otherwise, if we stored it as, for example, an array of player dyn props,
		// each bucket wouldn't spawn the "right" one - it would spawn the seahorse with the index
		// of the bucket number, if that makes sense
		// basically, each bucket would just iterate through the array,
		// regardless of what you actually stored in each bucket
		let seahorseIsBaby = target.hasComponent("minecraft:is_baby");
		let seahorseColor = target.getProperty("cyn_hao:base_id")
		let seahorseScale = target.getComponent("minecraft:scale").value
		let seahorseName = target.nameTag


		// perhaps instead of dyn props I could have used custom item component(s) to save these values,
		// but I couldn't be bothered putting in more effort than a quick glance,
		// and that quick glance did not yield any results
		// a side affect of this is that all the buckets list "Has Custom Properties" underneath,
		// but we have determined that to be acceptable at least for the time being
		itemStack.setDynamicProperty("cyn_hao:seahorse_name", seahorseName)
		itemStack.setDynamicProperty("cyn_hao:seahorse_baby", seahorseIsBaby)
		itemStack.setDynamicProperty("cyn_hao:seahorse_scale", seahorseScale)
		itemStack.setDynamicProperty("cyn_hao:seahorse_color", seahorseColor)

		// define the name of the bucket
		// reset silcrow at the start to make the text NOT be italicized
		let bucketString = "§rBucket of "

		// If the seahorse has a name, only display that
		if (seahorseName != "") {
			bucketString += seahorseName
		}



		// otherwise, display it's characteristics
		else {
			// Baby or Adult
			if (seahorseIsBaby) {
				bucketString += "Baby "
			}
			else {
				bucketString += "Adult "
			}



			// Scale
			if (seahorseScale < 0.8) {
				bucketString += "Small "
			}
			else if ((seahorseScale >= 0.8) && (seahorseScale <= 1.0)) {
				bucketString += "Medium "
			}
			else {
				bucketString += "Large "
			}


			
			// Color
			switch (target.getProperty("cyn_hao:base_id")) {
				case 0:
					bucketString += "§6Orange§r "
				break;

				case 1:
					bucketString += "§3Blue§r "
				break;

				case 2:
					bucketString += "§aGreen§r "
				break;

				case 3:
					bucketString += "§9Dark Blue§r "
				break;

				case 4:
					bucketString += "§dPurple§r "
				break;

				case 5:
					bucketString += "§bLight Blue§r "
				break;

				case 6:
					bucketString += "§eYellow§r "
				break;

				case 7:
					bucketString += "§cRed§r "
				break;

				default:
				break;	
			}



			// after all characteristics are determined,
			// set the name to reflect them
			bucketString += "Seahorse§r"
		}

		itemStack.nameTag = bucketString

		// required to update the item's name
		player.getComponent("minecraft:inventory").container.setItem(player.selectedSlotIndex, itemStack);

		// once the values are saved to the new bucket, despawn the seahorse
		target.remove()
	}
});









// placing
// get block face and such, spawn water, spawn seahorse, apply attributes to new seahorse if applicable

const MAX_INTERACTION_DISTANCE = 5; // Default Bedrock player interaction range (can be adjusted)

world.afterEvents.itemUse.subscribe((event) => {
    const { source, itemStack } = event;
	const player = source;
	let gameMode = player.getGameMode()

	// before anything, first check if the player is in spectator or adventure mode
	if ((gameMode == "Adventure") || (gameMode == "Spectator")) {
		// then they are not allowed to place blocks, so do nothing
		return;
	}

	// if the item being used is not our bucket of seahorse
    if ((itemStack == undefined) || (itemStack.typeId != "cyn_hao:seahorse_bucket")) {
		return;
	}

	
	const dimension = player.dimension;
	const targetBlockHit = player.getBlockFromViewDirection(); // Get the hit result

	// if there is no valid block to place
	if (targetBlockHit == undefined) {
		console.log("Could not find valid block to place seahorse. Aborting.")
		return;
	}

	

	const blockLocation = targetBlockHit.block.location;
	const blockFace = targetBlockHit.face;

	// Calculate the position where the block would be placed
	let placePosition = { x: blockLocation.x, y: blockLocation.y, z: blockLocation.z };

	switch (blockFace) {
		case Direction.Up:
			placePosition.y += 1;
			break;
		case Direction.Down:
			placePosition.y -= 1;
			break;
		case Direction.North:
			placePosition.z -= 1;
			break;
		case Direction.South:
			placePosition.z += 1;
			break;
		case Direction.East:
			placePosition.x += 1;
			break;
		case Direction.West:
			placePosition.x -= 1;
			break;
	}

	

	// Calculate the distance between the player's position and the placement position
	// while I would rather do without all this and simply use the "maxDistance" property of getBlockFromViewDirection(),
	// for some reason subbing that in using the exact same distance (the const above) 
	// results in gBFVD() being far shorter than it needs to be, like half as far
	// so just going to stick with this since it is always the right distance
	const playerLocation = player.location;
	const distance = Math.sqrt(
		Math.pow(playerLocation.x - placePosition.x, 2) +
		Math.pow(playerLocation.y - placePosition.y, 2) +
		Math.pow(playerLocation.z - placePosition.z, 2)
	);

	// Check if the distance is within the allowed range
	if (distance <= MAX_INTERACTION_DISTANCE) {
		// Place the water block
		dimension.setBlockType({ x: placePosition.x, y: placePosition.y, z: placePosition.z }, "minecraft:flowing_water"); // Corrected Vector3 format
		// play the water block placement sound
		dimension.playSound("bucket.empty_water", placePosition, { // Play sound at the placement position
						volume: 20.0, // Full volume
						pitch: 1.0   // Normal pitch
					});
	} else {
		// do nothing
		return;
	}
        

	let newSeahorse;
	// once the water is placed, spawn the new seahorse
	if (itemStack.getDynamicProperty("cyn_hao:seahorse_baby")) {
		// if it's a baby, we need to spawn it with the is_born
		newSeahorse = dimension.spawnEntity("cyn_hao:seahorse_small", { x: placePosition.x, y: placePosition.y, z: placePosition.z }, { spawnEvent: "minecraft:entity_born" })
	}
	else {
		newSeahorse = dimension.spawnEntity("cyn_hao:seahorse_small", { x: placePosition.x, y: placePosition.y, z: placePosition.z }, {spawnEvent: "cyn_hao:event_spawned_from_bucket" })
	}
	
	// once spawned, set it's properties
	// first, check if the item has any properties at all
	// the item from the creative menu does not
	// color is most important, so check that
	if (itemStack.getDynamicProperty("cyn_hao:seahorse_name") == undefined) {
		console.warn("No properties defined. Random seahorse will be spawned.")
	}
	else {
		// otherwise, if the properties are valid, set them

		// name tag cannot be empty
		// if it is, no name
		let seahorseName = itemStack.getDynamicProperty("cyn_hao:seahorse_name")
		if ((seahorseName != "") && (seahorseName != null) && (seahorseName != undefined)) {
			newSeahorse.nameTag = itemStack.getDynamicProperty("cyn_hao:seahorse_name")
		}
		
		// set color
		newSeahorse.setProperty("cyn_hao:base_id", itemStack.getDynamicProperty("cyn_hao:seahorse_color"))

		// scale must be done through events since it's read-only
		// handle scale with a fallback, since one time I saw scale listed as 0.4000000000034 or something
		// so try to round, but if somehow you get an invalid scale, set it to 0.75

		try {
			newSeahorse.triggerEvent(`cyn_hao:event_scale_${itemStack.getDynamicProperty("cyn_hao:seahorse_scale").toFixed(1)}`)
		}
		catch (error) {
			// If the specific event isn't defined, trigger the fallback
			console.warn(`Event 'cyn_hao:event_scale_${itemStack.getDynamicProperty("cyn_hao:seahorse_scale").toFixed(1)}' not defined for Small Seahorse. Triggering fallback scale of 0.75. Error: ${error}`);
			newSeahorse.triggerEvent("cyn_hao:event_scale_0.75");
		}
	}



	// once the seahorse has had it's properties assigned (if need be), 
	// delete the bucket item if the player is in any mode but creative
	if (gameMode != "Creative") {
		player.getComponent("minecraft:inventory").container.setItem(player.selectedSlotIndex, undefined);
	}
});