extends Node2D
const PhysicsFunc = preload("res://src/Utilities/Physic/PhysicsFunc.gd")
const PhysicsConst = preload("res://src/Utilities/Physic/PhysicsConst.gd")

# onready var slide_friction = 0.5

var mass = 1
var coupled_mass = mass
var spring_k = -1000
var start_y = 0
var y_velocity = 0
var friction = 0.91
# TODO Only store velocity coming to the springs orientation
var stored_incoming_velocity = 0
var coupled_body = null
var shock_ready = true


func _ready() -> void:
	start_y = self.position.y


# TODO Limit spring deformation


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _physics_process(delta: float) -> void:
	var bc = _body_contact()
	if !bc:
		shock_ready = true
	if bc && shock_ready:
		_Kinematic_Body_on_Spring()

	var spring_force = spring_k * (self.position.y - self.start_y)
	if coupled_body != null:
		coupled_mass = mass + coupled_body.mass
	else:
		coupled_mass = mass

	var weight_force = coupled_mass * PhysicsConst.gravity
	var result_force = weight_force + spring_force
	y_velocity = PhysicsFunc.two_step_euler(
		y_velocity, result_force, coupled_mass, delta
	)

	y_velocity *= friction

	self.position.y += y_velocity * delta


func _body_contact() -> bool:
	var areas: Array = $SpringSkin.get_overlapping_areas()
	for i in range(0, areas.size()):
		if areas[i].name == "BlobbySkin":
			coupled_body = areas[i].get_parent()
			return true
	coupled_body = null
	return false


func _Kinematic_Body_on_Spring() -> void:
	var a_velocity = stored_incoming_velocity
	var a_mass = coupled_body.mass
	var b_velocity = y_velocity
	var b_mass = mass
	y_velocity += PhysicsFunc.complete_unelastic_shock(
		a_velocity, b_velocity, a_mass, b_mass
	)
	stored_incoming_velocity = 0
	shock_ready = false


func _on_SpringSkin_area_exited(_area: Area2D) -> void:
	var displacement = self.position.y - self.start_y
	var potential_spring_energy = spring_k * 0.5 * pow(displacement, 2)
	var mass_ratio = 1 - mass / coupled_mass
	var transferred_kinetic_energy = potential_spring_energy * mass_ratio
	var kinetic_energy_in_velocity = (
		-sign(displacement)
		* sqrt(
			abs(
				2 * transferred_kinetic_energy / max(coupled_mass - mass, 0.001)
			)
		)
	)
	if coupled_body != null:
		coupled_body.velocity.y += kinetic_energy_in_velocity


func _on_EnteringVelocityDetector_area_entered(area: Area2D) -> void:
		if area.name == "BlobbySkin":
			if area.get_parent().velocity.y > 0:
				stored_incoming_velocity = area.get_parent().velocity.y
