extends CharacterBody2D

var speed = 300
var direction = Vector2.ZERO
var stick_duration = 3.0 # How long the arrow stays stuck to walls
var is_stuck = false
var stick_timer = 0.0

var initiated_by: Node2D = null
var player_owner: Node = null  # Like sword_projectile
var hit_targets = {}  # Track what we've already hit (Dictionary for O(1) lookup)

@onready var arrow_area = $ArrowArea # Assuming you have an Area2D node named ArrowArea
@onready var shadow = $Shadow # Assuming you have a Shadow node under the CharacterBody2D

# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	arrow_area.set_deferred("monitoring", true)
	# Connect area signals
	if arrow_area:
		arrow_area.body_entered.connect(_on_arrow_area_body_entered)
	$SfxArrowFire.play()
	call_deferred("_initialize_arrow")

func _initialize_arrow() -> void:
	var angle = direction.angle()
	self.rotation = angle - PI / 2 # Adjust for sprite orientation
	# Set initial rotation based on direction
	velocity = direction * speed # Set initial velocity to move the arrow
	
	# Calculate the offset for the shadow position, which should be below the arrow
	var shadow_offset = Vector2(0, 4) # Adjust the 16 to how far you want the shadow from the arrow (this is just an example)
	
	# Apply the rotation of the arrow to the shadow offset
	shadow.position += shadow_offset.rotated(-self.rotation)
	if abs(direction.x) == 1:
		shadow.scale.x = 0.26
		shadow.scale.y = 0.062
		
	elif abs(direction.x) > 0:
		shadow.scale.x = 0.18
		shadow.scale.y = 0.08
	else:
		shadow.scale.x = 0.1
		shadow.scale.y = 0.1
	
	# Calculate the shadow's scale based on the velocity or direction of the arrow
	#var velocity_magnitude = velocity.length()

	# Scale more in the horizontal direction if moving diagonally or horizontally
	#var scale_factor = 0.28 + abs(velocity.x) / velocity_magnitude  # Adjust the factor to your preference

	# Apply the scaling to the shadow
	shadow.rotation = -(angle - PI / 2)

func shoot(shoot_direction: Vector2, start_pos: Vector2, owner_player: Node = null) -> void:
	direction = shoot_direction.normalized()
	global_position = start_pos
	player_owner = owner_player
	initiated_by = owner_player

# Called every frame. 'delta' is the e	lapsed time since the previous frame.
func _process(delta: float) -> void:
	if is_stuck:
		# Handle fade out here if it's stuck
		stick_timer += delta
		if stick_timer >= stick_duration:
			# Start fading out after it sticks
			modulate.a = max(0, 1 - (stick_timer - stick_duration) / 1.0) # Fade out over 1 second
			if stick_timer >= stick_duration + 1.0: # Extra second for fade out
				queue_free() # Remove the arrow after fade out
	move_and_slide()

func _physics_process(_delta: float) -> void:
	# If the arrow is stuck, stop it from moving
	if is_stuck:
		velocity = Vector2.ZERO # Stop movement
		# Optional: disable further physics interaction by setting linear_velocity
		# move_and_slide(Vector2.ZERO)  # You can also use this to stop the character
		
func play_impact():
	$SfxImpactSound.play()

# Called when the arrow hits a wall or another object (like sword_projectile)
func _on_arrow_area_body_entered(body: Node2D) -> void:
	if is_stuck:
		return
	
	# Don't hit the owner
	if body == player_owner or body == initiated_by:
		return
	
	# Don't hit the same target twice
	if body in hit_targets:
		return
	
	# CRITICAL: Only the projectile owner (authority) should deal damage
	if player_owner and not player_owner.is_multiplayer_authority():
		return  # Only the authority (creator) of the projectile can deal damage
	
	# Add to hit_targets IMMEDIATELY to prevent multiple hits
	hit_targets[body] = true
	
	# Deal damage to players
	if body.is_in_group("player") and body.has_method("rpc_take_damage"):
		play_impact()
		var attacker_pos = player_owner.global_position if player_owner else global_position
		var player_peer_id = body.get_multiplayer_authority()
		if player_peer_id != 0:
			if multiplayer.is_server() and player_peer_id == multiplayer.get_unique_id():
				body.rpc_take_damage(20.0, attacker_pos)  # TODO: Get actual damage from player
			else:
				body.rpc_take_damage.rpc_id(player_peer_id, 20.0, attacker_pos)
		else:
			body.rpc_take_damage.rpc(20.0, attacker_pos)
		_stick_to_target(body)
		return
	
	# Deal damage to enemies
	if body.is_in_group("enemy") and body.has_method("rpc_take_damage"):
		var attacker_pos = player_owner.global_position if player_owner else global_position
		var damage = 20.0  # TODO: Get actual damage from player
		if player_owner and player_owner.character_stats:
			damage = player_owner.character_stats.damage
		
		# Check hit chance (based on player's DEX stat)
		var hit_roll = randf()
		var hit_chance = 0.95
		if player_owner and player_owner.character_stats:
			hit_chance = player_owner.character_stats.hit_chance
		var is_miss = hit_roll >= hit_chance
		
		if is_miss:
			if body.has_method("_show_damage_number"):
				body._show_damage_number(0.0, attacker_pos, false, true, false)  # is_miss = true
			_stick_to_target(body)
			return
		
		play_impact()
		var enemy_peer_id = body.get_multiplayer_authority()
		if enemy_peer_id != 0:
			if multiplayer.is_server() and enemy_peer_id == multiplayer.get_unique_id():
				body.rpc_take_damage(damage, attacker_pos, false)
			else:
				body.rpc_take_damage.rpc_id(enemy_peer_id, damage, attacker_pos, false)
		else:
			body.rpc_take_damage.rpc(damage, attacker_pos, false)
		_stick_to_target(body)
		return
	
	# Hit wall or other object
	$SfxImpactWall.play()
	_stick_to_wall()

func _stick_to_target(target: Node2D):
	# Stop the arrow
	velocity = Vector2.ZERO
	is_stuck = true
	stick_timer = 0.0
	arrow_area.set_deferred("monitoring", false)
	
	# Calculate the collision point - move arrow slightly back from its direction
	var collision_normal = -direction
	var offset_distance = 8
	var stick_position = global_position + (collision_normal * offset_distance)
	
	# Make arrow a child of the target to stick to it
	var global_rot = global_rotation
	get_parent().call_deferred("remove_child", self)
	target.call_deferred("add_child", self)
	self.set_deferred("global_position", stick_position)
	self.set_deferred("global_rotation", global_rot)

func _stick_to_wall():
	# Stop the arrow
	velocity = Vector2.ZERO
	is_stuck = true
	stick_timer = 0.0
	arrow_area.set_deferred("monitoring", false)
