import { world, system, Player } from "@minecraft/server";
import * as vehicleArrays from "../arrays/vehicle_arrays.js"

export function vehiclesMainComponents(vehicle) {
	const vehicleOnList = vehicleArrays.vehicleTypesList.includes(vehicle.typeId);
	if (!vehicleOnList) return;
	const rule = vehicleArrays.vehicleTypes[vehicle.typeId];
	if (!rule) return;
	const engine = vehicle.getProperty(rule.properties.engine);
	const hasRider = vehicle.getProperty(rule.properties.hasRider);
	if (rule.properties.fuelAmount) {
		const fuel = vehicle.getProperty(rule.properties.fuelAmount);
		updateFuelScoreboard(vehicle,rule.properties.fuelAmount, fuel);
	}
	let velocity = null;
	let hovering = null;
	let movementState = null;
	if (rule.properties.movementVelocity) {
		velocity = vehicle.getProperty(rule.properties.movementVelocity);
		updateVelocityScoreboard(vehicle,rule.properties.movementVelocity, velocity);
	}
	if (rule.properties.hovering) {
		hovering = vehicle.getProperty(rule.properties.hovering);
	}
	if (rule.properties.movementState) {
		movementState = vehicle.getProperty(rule.properties.movementState);
	}
	if (vehicle.typeId=="megaverse:motorbike") {
		if (engine=="unpowered"&&velocity!=0.00) {
			applyFriction(rule,vehicle,velocity);
		}
		if (engine=="powered") {
			handleMotorbikeMovement(rule,vehicle,hasRider,velocity);
		}
	}
	if (vehicle.typeId=="megaverse:rotorcraft") {
		const xRot = vehicle.getProperty("megaverse:vehicle_x_rotation");
		const zRot = vehicle.getProperty("megaverse:vehicle_z_rotation");
		const rideable = vehicle.getComponent("rideable");
		if (!rideable) return;
		const controllingSeat = rideable.controllingSeat;
		const riders = rideable.getRiders();
		const controllingRider = riders[controllingSeat];
		if (movementState=="autorotation") {
			handleRotorcraftAutorotation(rule,vehicle);
			applyRotorcraftTiltEquilibrium(rule,vehicle,xRot,zRot);
			return;
		}
		if (hasRider&&controllingRider) {
			if (controllingRider instanceof Player) {
				if (engine=="unpowered") {
					applyRotorcraftTiltEquilibrium(rule,vehicle,xRot,zRot);
				}
				if (engine=="powered"&&movementState!="grounded") {
					handleRotorcraftTilting(rule,vehicle,controllingRider);
					//handleRotorcraftWeapons(rule,vehicle,controllingRider,xRot,zRot);
				}
			}
		}
		else {
			applyRotorcraftTiltEquilibrium(rule,vehicle,xRot,zRot);
		}
	}
};
function updateFuelScoreboard(entity,prop,value) {
	if (value==null) return;
	const indicator = Math.floor(value*100);
	try {
		entity.runCommand(`scoreboard objectives add ${prop} dummy ${prop}`);
		entity.runCommand(`scoreboard players set @s[has_property={${prop}=${value}}] ${prop} ${indicator}`);
	}
	catch (e) {}
};
function updateVelocityScoreboard(entity,prop,value) {
	if (value==null) return;
	const indicator = Math.round(Math.abs(value)*100);
	try {
		entity.runCommand(`scoreboard objectives add ${prop} dummy ${prop}`);
		entity.runCommand(`scoreboard players set @s[has_property={${prop}=${value}}] ${prop} ${indicator}`);
	}
	catch (e) {}
};
function handleMotorbikeMovement(rule,vehicle,hasRider,velocity) {
	const riders = vehicle.getComponent("rideable").getRiders();
	const player = riders.find(r=>r instanceof Player);
	vehicle.runCommand(`titleraw @a[r=1.5] actionbar {"rawtext":[{"text":"§e"},{"translate":"action.interact.megaverse:fuel"},{"text":": "},{"score":{"name":"@s","objective":"${rule.properties.fuelAmount}"}},{"text":" "},{"translate":"action.interact.megaverse:velocity"},{"text":": "},{"score":{"name":"@s","objective":"${rule.properties.movementVelocity}"}}]}`);
	if (hasRider&&player) {
		player.playAnimation("animation.motorbike.player",{stopExpression: "!q.is_riding||v.is_first_person"});
		const movement = player.inputInfo?.getMovementVector?.();
		if (!movement) return;
		const normalizedX = Math.abs(movement.x)>=rule.vehicleInputs.threshold?(movement.x>0?1:-1):0;
		const normalizedY = Math.abs(movement.y)>=rule.vehicleInputs.threshold?(movement.y>0?1:-1):0;
		const key = `${normalizedX},${normalizedY}`;
		const inputType = rule.vehicleInputs.inputDirections[key]??"noAcceleration";
		const targetAccel = rule.vehicleInputs[inputType];
		adjustVelocityWithInput(rule,vehicle,velocity,targetAccel);
		applyImpulse(rule,vehicle,velocity,vehicle.isInWater?rule.vehicleInputs.movementOnWater:vehicle.isOnGround?rule.vehicleInputs.movementOnGround:rule.vehicleInputs.movementOnAir);
	}
	else {
		applyFriction(rule,vehicle,velocity);
	}
};
function adjustVelocityWithInput(rule,vehicle,currentVelocity,targetAccel) {
	// Direction switching: decelerate to 0 before switching
	if (targetAccel>rule.vehicleInputs.noAcceleration&&currentVelocity<0) {
		// Was moving backward, now trying to go forward
		const newVelocity = Math.min(0,currentVelocity+0.006);
		vehicle.setProperty(rule.properties.movementVelocity,newVelocity);
		return;
	}
	if (targetAccel<rule.vehicleInputs.noAcceleration&&currentVelocity>0) {
		// Was moving forward, now trying to go backward
		const newVelocity = Math.max(0,currentVelocity-0.006);
		vehicle.setProperty(rule.properties.movementVelocity,newVelocity);
		return;
	}
	if (targetAccel>rule.vehicleInputs.noAcceleration) {
		// Forward acceleration curve
		for (const [min,max,accel] of rule.velocityProperties.forwardAcceleration) {
			if (currentVelocity >= min && currentVelocity < max) {
				let next = currentVelocity+accel*targetAccel;
				if (vehicle.isInWater&&next>rule.maxVelocityInWater) {
					next = Math.max(next-0.005,rule.maxVelocityInWater);
				}
				next = Math.min(next,rule.maxDefaultVelocity);
				vehicle.setProperty(rule.properties.movementVelocity,next);
				return;
			}
		}
	}
	else if (targetAccel<rule.vehicleInputs.noAcceleration) {
		// Backward acceleration curve
		const absVelocity = Math.abs(currentVelocity);
		for (const [min,max,accel] of rule.velocityProperties.backwardAcceleration) {
			if (absVelocity >= min && absVelocity < max) {
				const next = Math.max(currentVelocity+accel*targetAccel,rule.minDefaultVelocity);
				vehicle.setProperty(rule.properties.movementVelocity,next);
				return;
			}
		}
	}
	else {
		for (const [min,max,decel] of rule.velocityProperties.deceleration) {
			if (currentVelocity>=min&&currentVelocity<max) {
				const next = Math.max(0,currentVelocity-decel);
				vehicle.setProperty(rule.properties.movementVelocity,next);
				return;
			}
		}
		// No input – decelerate naturally
		let decay = rule.velocityProperties.defaultDecay;
		if (currentVelocity>=rule.velocityProperties.driving.velocity) decay = rule.velocityProperties.driving.decay; // Slower decay when driving
		if (currentVelocity>=rule.velocityProperties.speeding.velocity) decay = rule.velocityProperties.speeding.decay; // Even slower decay when speeding
		const newVelocity = currentVelocity > 0
			? Math.max(0, currentVelocity-decay)
			: Math.min(0, currentVelocity+decay); // Slower decay for reverse
		vehicle.setProperty(rule.properties.movementVelocity,newVelocity);
	}
};
function applyFriction(rule,vehicle,velocity) {
	if (Math.abs(velocity)<0.02) return vehicle.setProperty(rule.properties.movementVelocity,0);
	const decay = velocity>0?0.002:0.001;
	const newVelocity = velocity>0
		? Math.max(0,velocity-decay)
		: Math.min(0,velocity+decay);
	vehicle.setProperty(rule.properties.movementVelocity,newVelocity);
	applyImpulse(rule,vehicle,velocity,vehicle.isInWater?rule.vehicleInputs.movementOnWater:vehicle.isOnGround?rule.vehicleInputs.movementOnGround:rule.vehicleInputs.movementOnAir);
};
function applyImpulse(rule,vehicle,velocity,scale=rule.vehicleInputs.movementOnDefault) {
	const dir = vehicle.getViewDirection();
	vehicle.applyImpulse({
		x: dir.x*velocity*scale,
		y: 0,
		z: dir.z*velocity*scale
	});
};



function handleRotorcraftWeapons(rule,vehicle,player,xRot=0,zRot=0) {
	const cooldown = vehicle.getProperty("megaverse:vehicle_missiles_cooldown");
	if (!player.isJumping||cooldown) return;
	let projectile = vehicle.dimension.spawnEntity("megaverse:thrown_draconic_war_dart", {
		x: vehicle.location.x+vehicle.getViewDirection().x,
		y: vehicle.location.y+vehicle.getViewDirection().y,
		z: vehicle.location.z+vehicle.getViewDirection().z
	});
	let callComponent = projectile.getComponent("minecraft:projectile");
	callComponent.owner = vehicle;
	projectile.triggerEvent("minecraft:become_missile");
	callComponent.shoot({
		x: vehicle.getViewDirection().x*5,
		y: vehicle.getViewDirection().y*5,
		z: vehicle.getViewDirection().z*5
	});
	vehicle.dimension.playSound("firework.launch",vehicle.location);
	vehicle.triggerEvent("minecraft:vehicle_missiles_cooldown_enabled");
	return projectile;
};

function handleRotorcraftControlledStates(rule,vehicle,controllingRider,hovering) {
	const pitch = controllingRider.getRotation().x;
	if (pitch<=-22.5&&hovering) vehicle.triggerEvent("minecraft:vehicle_hovering_disabled");
	if (pitch>=22.5&&hovering) vehicle.triggerEvent("minecraft:vehicle_hovering_disabled");
	if (pitch<22.5&&pitch>-22.5&&!vehicle.isOnGround&&!hovering) vehicle.triggerEvent("minecraft:vehicle_hovering_enabled");
};
function handleRotorcraftAutorotation(rule,vehicle) {
	let altitude = 0;
	if (!vehicle.isOnGround) altitude = 0.07;
	if (altitude!=0) return vehicle.applyImpulse({x:0,y:altitude,z:0});
};
function handleRotorcraftTilting(rule, vehicle, player) {
	const movement = player.inputInfo.getMovementVector();
	if (!movement) return;
	const normalizedX = Math.abs(movement.x) >= rule.vehicleInputs.threshold ? (movement.x > 0 ? 1 : -1) : 0;
	const normalizedY = Math.abs(movement.y) >= rule.vehicleInputs.threshold ? (movement.y > 0 ? 1 : -1) : 0;
	const inputKey = `${normalizedX},${normalizedY}`;
	const inputType = rule.vehicleInputs.inputDirections[inputKey] ?? "noAcceleration";
	const acceleration = rule.vehicleInputs[inputType] ?? 0;
	/*const forward = vehicle.getViewDirection();
	const right = { x: forward.z, y: 0, z: -forward.x };*/
	const forward = { x: 0, y: 0, z: 1 }; // North
	const right = { x: 1, y: 0, z: 0 };   // East
	let moveDir = { x: 0, y: 0, z: 0 };
	if (normalizedY !== 0) {
		moveDir.x += forward.x * normalizedY;
		moveDir.z += forward.z * normalizedY;
	}
	if (normalizedX !== 0) {
		moveDir.x += right.x * normalizedX;
		moveDir.z += right.z * normalizedX;
	}
	const magnitude = Math.hypot(moveDir.x, moveDir.z);
	if (magnitude > 0) {
		moveDir.x /= magnitude;
		moveDir.z /= magnitude;
	}
	const scale = 1.0;
	const targetTiltX = Math.floor(moveDir.x * acceleration * scale);
	const targetTiltZ = Math.floor(moveDir.z * acceleration * scale);
	const easingStep = 1; // Lower value = slower tilt
	const currentTiltX = vehicle.getProperty("megaverse:vehicle_x_rotation") ?? 0;
	const currentTiltZ = vehicle.getProperty("megaverse:vehicle_z_rotation") ?? 0;
	let newTiltX = currentTiltX;
	let newTiltZ = currentTiltZ;
	if (targetTiltX > currentTiltX) {
		newTiltX = Math.min(currentTiltX + easingStep, targetTiltX);
	}
	else if (targetTiltX < currentTiltX) {
		newTiltX = Math.max(currentTiltX - easingStep, targetTiltX);
	}
	if (inputKey === "0,0" && Math.abs(newTiltX) < 0.1) newTiltX = 0;
	if (inputKey === "0,0" && Math.abs(newTiltZ) < 0.1) newTiltZ = 0;
	if (targetTiltZ > currentTiltZ) {
		newTiltZ = Math.min(currentTiltZ + easingStep, targetTiltZ);
	}
	else if (targetTiltZ < currentTiltZ) {
		newTiltZ = Math.max(currentTiltZ - easingStep, targetTiltZ);
	}
	vehicle.setProperty("megaverse:vehicle_x_rotation", newTiltX);
	vehicle.setProperty("megaverse:vehicle_z_rotation", newTiltZ);
	//player.sendMessage(`X: ${newTiltX.toFixed(2)} & Z: ${newTiltZ.toFixed(2)}`);
};
function applyRotorcraftTiltEquilibrium(rule, vehicle, xRot = 0, zRot = 0) {
	if (Math.abs(xRot)<1) vehicle.setProperty("megaverse:vehicle_x_rotation",0);
	else {
		const xDecay = xRot>0?1:0.5;
		const newXRot = xRot>0?Math.max(0,xRot-xDecay):Math.min(0,xRot+xDecay);
		vehicle.setProperty("megaverse:vehicle_x_rotation",newXRot);
	}
	if (Math.abs(zRot)<1) vehicle.setProperty("megaverse:vehicle_z_rotation",0);
	else {
		const zDecay = zRot>0?1:0.5;
		const newZRot = zRot>0?Math.max(0,zRot-zDecay):Math.min(0,zRot+zDecay);
		vehicle.setProperty("megaverse:vehicle_z_rotation",newZRot);
	}
};
/*function handleRotorcraftTilting(rule,vehicle,player) {
	const movement = player.inputInfo.getMovementVector();
	if (!movement) return;
	const normalizedX = Math.abs(movement.x)>=rule.vehicleInputs.threshold?(movement.x>0?1:-1):0;
	const normalizedY = Math.abs(movement.y)>=rule.vehicleInputs.threshold?(movement.y>0?1:-1):0;
	const inputKey = `${normalizedX},${normalizedY}`;
	const inputType = rule.vehicleInputs.inputDirections[inputKey]??"noAcceleration";
	const acceleration = rule.vehicleInputs[inputType]??0;
	const forward = vehicle.getViewDirection();
	const right = { x: forward.z, y: 0, z: -forward.x };
	let moveDir = { x: 0, y: 0, z: 0 };
	if (normalizedY!=0) {
		moveDir.x += forward.x*normalizedY;
		moveDir.z += forward.z*normalizedY;
	}
	if (normalizedX!=0) {
		moveDir.x += right.x*normalizedX;
		moveDir.z += right.z*normalizedX;
	}
	const magnitude = Math.hypot(moveDir.x, moveDir.z);
	if (magnitude > 0) {
		moveDir.x /= magnitude;
		moveDir.z /= magnitude;
	}
	const scale = 1.0;
	player.sendMessage(`X: ${Math.floor(moveDir.x*acceleration*scale)} & Z: ${Math.floor(moveDir.z*acceleration*scale)}`);
	vehicle.setProperty("megaverse:vehicle_x_rotation",Math.floor(moveDir.x*acceleration*scale));
	vehicle.setProperty("megaverse:vehicle_z_rotation",Math.floor(moveDir.z*acceleration*scale));
};*/
function handleVehicleWASDInputControl(rule,vehicle,player,navigationState,isOnGround) {
	const movement = player.inputInfo.getMovementVector();
	if (!movement) return;
	const normalizedX = Math.abs(movement.x) >= rule.threshold ? (movement.x > 0 ? 1 : -1) : 0;
	const normalizedY = Math.abs(movement.y) >= rule.threshold ? (movement.y > 0 ? 1 : -1) : 0;
	const inputKey = `${normalizedX},${normalizedY}`;
	const inputType = rule.inputDirections[inputKey] ?? "noAcceleration";
	const acceleration = rule[inputType]??0;
	// Get forward direction
	const forward = vehicle.getViewDirection();
	// Calculate right vector (perpendicular to forward vector on XZ plane)
	const right = { x: forward.z, y: 0, z: -forward.x };
	// Calculate final direction vector from input
	let moveDir = { x: 0, y: 0, z: 0 };
	if (normalizedY !== 0) {
		moveDir.x += forward.x * normalizedY;
		moveDir.z += forward.z * normalizedY;
	}
	if (normalizedX !== 0) {
		moveDir.x += right.x * normalizedX;
		moveDir.z += right.z * normalizedX;
	}
	// Normalize moveDir to prevent faster diagonals
	const magnitude = Math.hypot(moveDir.x, moveDir.z);
	if (magnitude > 0) {
		moveDir.x /= magnitude;
		moveDir.z /= magnitude;
	}
	// Apply scale depending on ground status
	const scale = vehicle.isInWater?rule.movementOnWater:isOnGround?rule.movementOnGround:rule.movementOnAir;
	// Final impulse
	const pitch = player.getRotation().x;
	let altitude = 0;
	if (pitch<-22.5) {
		const upPitch = Math.max(Math.min(pitch,-22.5),-90);
		const t = (upPitch+22.5)/(-90+22.5);
		altitude = lerp(0.015,0.05,t);
	}
	else if (pitch>35) {
		const downPitch = Math.min(Math.max(pitch,35),90);
		const t = (downPitch-22.5)/(90-35);
		altitude = lerp(-0.015,-0.03,t);
	}
	else {
		altitude = -vehicle.getVelocity().y;
	}
	if (pitch<-22.5&&navigationState!="air_controlled") vehicle.triggerEvent("minecraft:vehicle_air_controlled");
	if (pitch>35&&isOnGround&&navigationState!="grounded") vehicle.triggerEvent("minecraft:vehicle_grounded");
	vehicle.applyImpulse({
		x: moveDir.x*acceleration*scale,
		y: altitude,
		z: moveDir.z*acceleration*scale
	});
	//player.sendMessage(`vehicle grounded: ${isOnGround}`);
	//notice: vehicle is on ground but somehow pitch won't do shit until it moves.
	/*Note to self:
		Split Functions of Pitch, Ground & Air Controls.
	*/
};
function lerp(a,b,t) {
	return a+(b-a)*t;
};