extends Node2D

# Sword Slash - Swings around player and deals damage

@export var damage: float = 20.0
@export var swing_speed: float = 720.0 # Degrees per second
@export var swing_radius: float = 40.0 # Distance from player center (closer swing)
@export var lifetime: float = 0.3 # How long the slash lasts

var swing_angle: float = 0.0 # Current angle
var swing_start_angle: float = 0.0 # Starting angle
var swing_arc: float = 180.0 # Total arc to swing (180 degrees)
var elapsed_time: float = 0.0
var player_owner: Node = null
var hit_targets = {} # Track what we've already hit (Dictionary for O(1) lookup)

@onready var sprite = $Sprite2D
@onready var hit_area = $Area2D

func _ready():
	# Connect area signals
	if hit_area:
		hit_area.body_entered.connect(_on_body_entered)
	
	# Set initial rotation
	rotation = deg_to_rad(swing_start_angle)

func setup(start_angle: float, owner_player: Node, arc_direction: float = 1.0):
	swing_start_angle = start_angle
	swing_angle = start_angle
	player_owner = owner_player
	swing_arc = 180.0 * arc_direction # Positive or negative arc
	rotation = deg_to_rad(swing_start_angle)

func _physics_process(delta):
	elapsed_time += delta
	
	# Check lifetime
	if elapsed_time >= lifetime:
		queue_free()
		return
	
	# Calculate swing progress (0 to 1)
	var progress = elapsed_time / lifetime
	
	# Swing the sword in an arc
	swing_angle = swing_start_angle + (swing_arc * progress)
	rotation = deg_to_rad(swing_angle)
	
	# Position around player if we have one
	if player_owner and is_instance_valid(player_owner):
		var offset = Vector2(swing_radius, 0).rotated(deg_to_rad(swing_angle))
		global_position = player_owner.global_position + offset

func _on_body_entered(body):
	# Don't hit the owner
	if body == player_owner:
		return
	
	# Don't hit the same target twice - use Dictionary for O(1) lookup to prevent race conditions
	if body in hit_targets:
		return
	
	# Add to hit_targets IMMEDIATELY to prevent multiple hits (mark as hit before processing)
	hit_targets[body] = true
	
	# Friendly fire: only skip when owner is also a player. Enemies can hit players.
	if body.is_in_group("player") and body.has_method("take_damage"):
		if player_owner and player_owner.is_in_group("player"):
			return # Owner is player → pass through, no damage
		# Owner is enemy → deal damage to player
		var attacker_pos = player_owner.global_position if player_owner and is_instance_valid(player_owner) else global_position
		var player_peer_id = body.get_multiplayer_authority()
		if player_peer_id != 0:
			if multiplayer.get_unique_id() == player_peer_id:
				body.rpc_take_damage(damage, attacker_pos, false, false)
			else:
				body.rpc_take_damage.rpc_id(player_peer_id, damage, attacker_pos, false, false)
		else:
			body.rpc_take_damage.rpc(damage, attacker_pos, false, false)
		return

	# Deal damage to boxes or other damageable objects
	if "health" in body:
		# Boxes have health property
		body.health -= damage
		if body.health <= 0 and body.has_method("_break_into_pieces"):
			body._break_into_pieces()
		print("Sword hit object: ", body.name)
	
	# Push the hit target away slightly
	if body is CharacterBody2D:
		var knockback_dir = (body.global_position - global_position).normalized()
		if body.is_in_group("player") and "is_dead" in body and body.is_dead:
			# Corpse: reduced force, sync to victim's client so they see the push
			const CORPSE_KNOCKBACK: float = 50.0
			var pid = body.get_multiplayer_authority()
			if pid == multiplayer.get_unique_id():
				body.rpc_apply_corpse_knockback(knockback_dir.x, knockback_dir.y, CORPSE_KNOCKBACK)
			elif pid != 0:
				body.rpc_apply_corpse_knockback.rpc_id(pid, knockback_dir.x, knockback_dir.y, CORPSE_KNOCKBACK)
			else:
				body.rpc_apply_corpse_knockback.rpc(knockback_dir.x, knockback_dir.y, CORPSE_KNOCKBACK)
		else:
			body.velocity = knockback_dir * 200.0
