extends CharacterBody2D

var friction = 8.0 # Lower values make the slowdown more gradual
var is_collected = false
var bounceTimer = 0.0
var timeBeforePickup = 0.8
@onready var damage_number_scene = preload("res://assets/scripts/components/damage_number.tscn")

# Z-axis variables
var positionZ = 4.0 # Start slightly in the air
var velocityZ = 10.0 # Initial upward velocity
var accelerationZ = -300.0 # Gravity
var bounceRestitution = 0.6 # How much bounce energy is retained (0-1)
var minBounceVelocity = 40.0 # Minimum velocity needed to bounce

var bodyToPickUp:Node2D = null

var sync_position := Vector2()
var sync_velocity := Vector2()
var sync_positionZ: float = 4.0
var sync_velocityZ: float = 10.0

func _ready() -> void:
	add_to_group("coins")
	$Area2DCollision.set_deferred("monitoring", false)
	update_sprite_scale()
	
	# Start animation
	$AnimationPlayer.play("idle")

func _process(delta: float) -> void:
	if bodyToPickUp != null and !is_collected and timeBeforePickup == 0 and positionZ < 5:
		visible = false
		$SfxCoinCollect.play()
		is_collected = true
		$Area2DCollision.set_deferred("monitoring", false)
		
		var damage_number = damage_number_scene.instantiate() as Label
		if damage_number:
			get_tree().current_scene.add_child(damage_number)
			damage_number.global_position = global_position + Vector2(0, -16)
			if "direction" in damage_number:
				damage_number.direction = Vector2(0, -1)
			damage_number.move_duration = 1.0
			if "label" in damage_number:
				damage_number.label = "+1 COIN"
			if "color" in damage_number:
				damage_number.color = Color.YELLOW
		if "stats" in bodyToPickUp:
			bodyToPickUp.stats.add_coin(1)
		await $SfxCoinCollect.finished
		call_deferred("queue_free")
		return
	if is_collected:
		return
	if timeBeforePickup > 0.0:
		timeBeforePickup -= delta
		if timeBeforePickup < 0:
			$Area2DCollision.set_deferred("monitoring", true)
			timeBeforePickup = 0
	if bounceTimer > 0.0:
		bounceTimer -= delta
		if bounceTimer < 0:
			bounceTimer = 0
			
	# Update vertical movement
	velocityZ += accelerationZ * delta
	positionZ += velocityZ * delta
	
	# Ground collision and bounce
	if positionZ <= 0:
		velocity = velocity.lerp(Vector2.ZERO, 1.0 - exp(-friction * delta)) # only slow down if on floor
		positionZ = 0
		if abs(velocityZ) > minBounceVelocity:
			#print(velocityZ)
			$SfxCoinBounce.volume_db = -1 + (-10 - (velocityZ * 0.1))
			$SfxCoinBounce.play()
			velocityZ = -velocityZ * bounceRestitution
		else:
			velocityZ = 0
	
	update_sprite_scale()
	move_and_slide()
'
func _physics_process(delta: float) -> void:
	if multiplayer.is_server():
		for peer_id in multiplayer.get_peers():
			sync_coin.rpc_id(peer_id, position, velocity, positionZ, velocityZ)
	if !multiplayer.is_server():
		position = position.lerp(sync_position, delta * 15.0)
		velocity = velocity.lerp(sync_velocity, delta * 15.0)
		positionZ = sync_positionZ
		velocityZ = sync_velocityZ
		if positionZ <= 0:
			velocity = velocity.lerp(Vector2.ZERO, 1.0 - exp(-friction * delta)) # only slow down if on floor
			positionZ = 0
		if abs(velocityZ) > minBounceVelocity:
			#print(velocityZ)
			$SfxCoinBounce.volume_db = -1 + (-10 - (velocityZ * 0.1))
			$SfxCoinBounce.play()
		
		update_sprite_scale()
	pass
'
@rpc("unreliable")
func sync_coin(pos: Vector2, vel: Vector2, posZ: float, velZ: float):
	sync_position = pos
	sync_velocity = vel
	sync_positionZ = posZ
	sync_velocityZ = velZ
	pass
	
func update_sprite_scale() -> void:
	# Calculate scale based on height
	# Maximum height will have scale 1.3, ground will have scale 1.0
	var height_factor = positionZ / 50.0 # Assuming 20 is max height
	var posY = 0.0 + (2 * positionZ)
	var sc = 1.0 + (0.8 * height_factor)
	$Sprite2D.scale = Vector2(sc, sc)
	$Sprite2D.position.y = -posY

func _on_area_2d_collision_body_entered(_body: Node2D) -> void:
	if bounceTimer == 0:
		$SfxCoinBounce.play()
		bounceTimer = 0.08
		# inverse the direction and slow down slightly
		var collision_shape = $Area2DCollision.get_overlapping_bodies()
		
		if collision_shape.size() > 0:
			var collider = collision_shape[0]
			var normal = (global_position - collider.global_position).normalized()
			velocity = velocity.bounce(normal)
	
	pass # Replace with function body.

@rpc("any_peer", "reliable")
func pick_up(_char: CharacterBody2D):
	# does nothing... handled by coin itself!
	return false

func _on_area_2d_pickup_body_entered(body: Node2D) -> void:
	if !is_collected:
		bodyToPickUp = body.get_parent()
		
	pass # Replace with function body.


func _on_area_2d_pickup_body_exited(_body: Node2D) -> void:
	bodyToPickUp = null
	pass # Replace with function body.


func _on_area_2d_pickup_area_entered(area: Area2D) -> void:
	if !is_collected:
		bodyToPickUp = area.get_parent()
	pass # Replace with function body.


func _on_area_2d_pickup_area_exited(_area: Area2D) -> void:
	bodyToPickUp = null
	pass # Replace with function body.
