import { world, system , BlockComponent } from '@minecraft/server';
import { ActionFormData, ModalFormData } from '@minecraft/server-ui';

export function physics (ball) {
	var x = ball.location.x
	var y = ball.location.y
	var z = ball.location.z
	var vx = ball.getDynamicProperty("vx")
	var vy = ball.getDynamicProperty("vy")
	var vz = ball.getDynamicProperty("vz")
	var playerName = ball.getDynamicProperty("owner")
	var player = world.getDimension("Overworld").getPlayers({name: playerName})[0]
	vy += -0.1
	if (world.getDimension("overworld").getBlock(ball.location)?.typeId != "minecraft:air") ball.runCommand("/tp @s ~~0.5~")
	var precision = 1000/world.getDimension("Overworld").getEntities({families:["fara:ball"]}).length
	for (let i = 0 ; i <= precision; i++){
		var segment = i/precision
		var facingBlock = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment})?.typeId
		if (facingBlock != "minecraft:air") {
			//ball.runCommand("/say §efound a block! i="+i+", block: "+facingBlock)
			break
		} else if (facingBlock == "minecraft:air" && i%1000 == 0) {
			//ball.runCommand("/say §4Not found a block! i="+i+", block: "+facingBlock+" at "+(x+vx*segment)+" "+(y+vy*segment)+" "+(z+vz*segment))
		}
	}
	let vector = {
		x:x+vx*segment,
		y:y+vy*segment,
		z:z+vz*segment
	}
	if (!facingBlock) {var facingBlock = "minecraft:air"}
	if (facingBlock !="minecraft:air") {
		var xside1 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().x-0.5
		var xside2 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().x+0.5
		var yside1 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().y-0.5
		var yside2 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().y+0.5
		var zside1 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().z-0.5
		var zside2 = world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment}).center().z+0.5
		
		if ( vector.x != x) {var tside_x1 = (xside1 - x)/(vector.x-x)} else {var tside_x1 = (xside1 - x)/(vector.x-x+0.001)}
		if ( vector.x != x) {var tside_x2 = (xside2 - x)/(vector.x-x)} else {var tside_x2 = (xside2 - x)/(vector.x-x+0.001)}
		if ( vector.y != y) {var tside_y1 = (yside1 - y)/(vector.y-y)} else {var tside_y1 = (yside1 - y)/(vector.y-y+0.001)}
		if ( vector.y != y) {var tside_y2 = (yside2 - y)/(vector.y-y)} else {var tside_y2 = (yside2 - y)/(vector.y-y+0.001)}
		if ( vector.z != z) {var tside_z1 = (zside1 - z)/(vector.z-z)} else {var tside_z1 = (zside1 - z)/(vector.z-z+0.001)}
		if ( vector.z != z) {var tside_z2 = (zside2 - z)/(vector.z-z)} else {var tside_z2 = (zside2 - z)/(vector.z-z+0.001)}
		
		var xline_x1 = x + tside_x1*(vector.x-x)
		var xline_x2 = x + tside_x2*(vector.x-x)
		var xline_y1 = x + tside_y1*(vector.x-x)
		var xline_y2 = x + tside_y2*(vector.x-x)
		var xline_z1 = x + tside_z1*(vector.x-x)
		var xline_z2 = x + tside_z2*(vector.x-x)
		
		var yline_x1 = y + tside_x1*(vector.y-y)
		var yline_x2 = y + tside_x2*(vector.y-y)
		var yline_y1 = y + tside_y1*(vector.y-y)
		var yline_y2 = y + tside_y2*(vector.y-y)
		var yline_z1 = y + tside_z1*(vector.y-y)
		var yline_z2 = y + tside_z2*(vector.y-y)
		
		var zline_x1 = z + tside_x1*(vector.z-z)
		var zline_x2 = z + tside_x2*(vector.z-z)
		var zline_y1 = z + tside_y1*(vector.z-z)
		var zline_y2 = z + tside_y2*(vector.z-z)
		var zline_z1 = z + tside_z1*(vector.z-z)
		var zline_z2 = z + tside_z2*(vector.z-z)
		
		//Calculating which distance is shorter to determine which collision is sooner
		var xdistance1 = Math.sqrt(Math.pow(x-xline_x1,2)+Math.pow(y-yline_x1,2)+Math.pow(z-zline_x1,2))
		var xdistance2 = Math.sqrt(Math.pow(x-xline_x2,2)+Math.pow(y-yline_x2,2)+Math.pow(z-zline_x2,2))
		var ydistance1 = Math.sqrt(Math.pow(x-xline_y1,2)+Math.pow(y-yline_y1,2)+Math.pow(z-zline_y1,2))
		var ydistance2 = Math.sqrt(Math.pow(x-xline_y2,2)+Math.pow(y-yline_y2,2)+Math.pow(z-zline_y2,2))
		var zdistance1 = Math.sqrt(Math.pow(x-xline_z1,2)+Math.pow(y-yline_z1,2)+Math.pow(z-zline_z1,2))
		var zdistance2 = Math.sqrt(Math.pow(x-xline_z2,2)+Math.pow(y-yline_z2,2)+Math.pow(z-zline_z2,2))
		if (world.getDimension("overworld").getBlock({x:x+vx*segment-0.5, y:y+vy*segment, z:z+vz*segment}).typeId != "minecraft:air") xdistance1 = 9999
		if (world.getDimension("overworld").getBlock({x:x+vx*segment+0.5, y:y+vy*segment, z:z+vz*segment}).typeId != "minecraft:air") xdistance2 = 9999
		if (world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment-0.5, z:z+vz*segment}).typeId != "minecraft:air") ydistance1 = 9999
		if (world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment+0.5, z:z+vz*segment}).typeId != "minecraft:air") ydistance2 = 9999
		if (world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment-0.5}).typeId != "minecraft:air") zdistance1 = 9999
		if (world.getDimension("overworld").getBlock({x:x+vx*segment, y:y+vy*segment, z:z+vz*segment+0.5}).typeId != "minecraft:air") zdistance2 = 9999
		
		var closestCollision = Math.min(xdistance1,xdistance2,ydistance1,ydistance2,zdistance1,zdistance2)
		if ((xline_x1 == xside1) && (yline_x1 >= yside1) && (yline_x1 <= yside2) && (zline_x1 >= zside1) && (zline_x1 <= zside2)) {
			if (closestCollision == xdistance1) {var collisionX = "x1"}
		}
		if ((xline_x2 == xside2) && (yline_x2 >= yside1) && (yline_x2 <= yside2) && (zline_x2 >= zside1) && (zline_x2 <= zside2)) {
			if ( closestCollision == xdistance2) {var collisionX = "x2"}
		}
	
		if ((xline_y1 >= xside1) && (xline_y1 <= xside2) && (yline_y1 == yside1) && (zline_y1 >= zside1) && zline_y1 <= zside2) {
			if ( closestCollision == ydistance1 ) {var collisionY = "y1"}
		}
		if (xline_y2 >= xside1 && xline_y2 <= xside2 && yline_y2 == yside2 && zline_y2 >= zside1 && zline_y2 <= zside2) {
			if ( closestCollision == ydistance2 ) {var collisionY = "y2"}
		}
	
		if (xline_z1 >= xside1 && xline_z1 <= xside2 && yline_z1 >= yside1 && yline_z1 <= yside2 && zline_z1 == zside1) {
			if ( closestCollision == zdistance1 ) {var collisionZ = "z1"}
		}
		if (xline_z2 >= xside1 && xline_z2 <= xside2 && yline_z2 >= yside1 && yline_z2 <= yside2 && zline_z2 == zside2) {
			if ( closestCollision == zdistance2 ) {var collisionZ = "z2"}
		}
		
		// world.getDimension("Overworld").runCommand("/say collision: "+closestCollision)
		if (collisionX == "x1") ball.teleport({x:xline_x1-0.1,y:yline_x1,z:zline_x1})
		else if (collisionX == "x2") ball.teleport({x:xline_x2+0.1,y:yline_x2,z:zline_x2})
		if (collisionY == "y1") ball.teleport({x:xline_y1,y:yline_y1-0.1,z:zline_y1})
		else if (collisionY == "y2") ball.teleport({x:xline_y2,y:yline_y2+0.1,z:zline_y2})
		if (collisionZ == "z1") ball.teleport({x:xline_z1,y:yline_z1,z:zline_z1-0.1})
		else if (collisionZ == "z2") ball.teleport({x:xline_z2,y:yline_z2,z:zline_z2+0.1})
	}
	if (facingBlock != "minecraft:air" && (collisionX == "x1" || collisionX == "x2")) {
		
		vx = -vx*0.8
		if (Math.abs(vx>0.2)) ball.runCommand("/playsound fall.basalt @a[r=30] ~~~ 1 "+(1+0.5*(Math.random()-0.5)))
		
	}
	if ((facingBlock != "minecraft:air" && Math.abs(vy) > 0 && (collisionY == "y1" || collisionY == "y2"))) {

		vy = -vy*0.8
		if (Math.abs(vy>0.2)) ball.runCommand("/playsound fall.basalt @a[r=30] ~~~ 1 "+(1+0.5*(Math.random()-0.5)))

	}
	if (facingBlock != "minecraft:air" && (collisionZ == "z1" || collisionZ == "z2")) {

		vz = -vz*0.8
		if (Math.abs(vz>0.2)) ball.runCommand("/playsound fall.basalt @a[r=30] ~~~ 1 "+(1+0.5*(Math.random()-0.5)))

	}
	// var entity = world.getDimension("Overworld").getEntitiesFromRay(ball.location,{x:vx,y:vy,z:vz},{
		// maxDistance: 2*Math.sqrt(Math.pow(vx,2)+Math.pow(vy,2)+Math.pow(vz,2)),
		// families: ["fara:enemy"] })[0]?.entity
		var entity = world.getDimension("overworld").getEntities({
			location: ball.location,
			maxDistance: 2,
			families:["fara:enemy"]
		})[0]
	if (entity) {
		var originalSpeed = Math.sqrt(Math.pow(vx,2)+Math.pow(vy,2)+Math.pow(vz,2))
		vx = ball.location.x-entity.location.x
		vz = ball.location.z-entity.location.z
		var k = Math.sqrt((Math.pow(originalSpeed,2)-Math.pow(vy,2))/(Math.pow(vx,2)+Math.pow(vz,2)))
		vx = k*vx
		vz = k*vz
		vy = -vy*0.8
		//ball.runCommand("/say vx: "+ball.location.x+"entityx: "+entity.location.x)
		//ball.runCommand("/say k: "+k+", original speed: "+originalSpeed+", new speed: "+Math.sqrt(Math.pow(vx,2)+Math.pow(vy,2)+Math.pow(vz,2)))
	}
	vx = vx*0.99
	vy = vy*0.99
	vz = vz*0.99
	//if (Math.abs(vy)>0.1) ball.runCommand("/say ball x:"+Math.floor(x*100)/100+", y:"+Math.floor(y*100)/100+", z"+Math.floor(z*100)/100+", vx:"+Math.floor(vx*100)/100+", vy:"+Math.floor(vy*100)/100+", vz:"+Math.floor(vz*100)/100)
	if (Math.abs(vy) < 0.2 && world.getDimension("overworld").getBlock({x:ball?.location.x, y:ball?.location.y-0.1,z:ball?.location.z})?.typeId != "minecraft:air") { vy = 0}
	ball.clearVelocity()
	ball.applyImpulse({x:vx,y:vy,z:vz})
	ball.setDynamicProperty("vx",vx)
	ball.setDynamicProperty("vy",vy)
	ball.setDynamicProperty("vz",vz)
	world.scoreboard.getObjective("debug").setScore("x",x*100)
	world.scoreboard.getObjective("debug").setScore("y",y*100)
	world.scoreboard.getObjective("debug").setScore("z",z*100)
	world.scoreboard.getObjective("debug").setScore("vx",vx*100)
	world.scoreboard.getObjective("debug").setScore("vy",vy*100)
	world.scoreboard.getObjective("debug").setScore("vz",vz*100)
	
};