extends Node2D

# Axe Swing - stays on player, plays $SwingAnimation by direction (attack_down, attack_right, etc.).
# Uses equipped axe texture/frame. On hit: deal damage, spawn damage_effect_axe.
# Duration ~0.27s to match player AXE/SWORD animation.

const LIFETIME: float = 0.27
const DIR_ANIMATIONS: Array = [
	"attack_right", # 0: right
	"attack_down_right", # 1
	"attack_down", # 2
	"attack_down_left", # 3
	"attack_left", # 4
	"attack_up_left", # 5
	"attack_up", # 6
	"attack_up_right" # 7
]

@export var damage: float = 20.0
var elapsed_time: float = 0.0
var player_owner: Node = null
var hit_targets: Dictionary = {}

var damage_effect_axe_scene: PackedScene = preload("res://scenes/damage_effect_axe.tscn")

@onready var sprite: Sprite2D = $Sprite2D
@onready var hit_area: Area2D = $DamageArea
@onready var swing_animation: AnimationPlayer = $SwingAnimation

func _ready() -> void:
	if hit_area:
		if not hit_area.body_entered.is_connected(_on_damage_area_body_entered):
			hit_area.body_entered.connect(_on_damage_area_body_entered)
	if has_node("AttackSwosh"):
		$AttackSwosh.play()

func setup(attack_direction: Vector2, owner_player: Node, _arc_direction: float = 1.0, axe_item: Item = null) -> void:
	player_owner = owner_player
	if owner_player and owner_player.character_stats:
		damage = owner_player.character_stats.damage
	# Use equipped axe texture and frame
	if axe_item and sprite:
		var tex = load(axe_item.spritePath) as Texture2D
		if tex:
			sprite.texture = tex
		sprite.hframes = axe_item.spriteFrames.x if axe_item.spriteFrames.x > 0 else 20
		sprite.vframes = axe_item.spriteFrames.y if axe_item.spriteFrames.y > 0 else 14
		sprite.frame = axe_item.spriteFrame
	# Pick direction animation: 8 sectors by angle
	var dir_norm = attack_direction.normalized()
	var angle = dir_norm.angle()
	var sector = int(round(angle / (TAU / 8.0))) % 8
	if sector < 0:
		sector += 8
	var anim_name = DIR_ANIMATIONS[sector] if sector < DIR_ANIMATIONS.size() else "attack_down"
	if swing_animation and swing_animation.has_animation(anim_name):
		swing_animation.play(anim_name)

func _process(delta: float) -> void:
	elapsed_time += delta
	if player_owner and is_instance_valid(player_owner):
		global_position = player_owner.global_position
	if elapsed_time >= LIFETIME:
		queue_free()

func _on_damage_area_body_entered(body: Node2D) -> void:
	if body == player_owner:
		return
	if body in hit_targets:
		return
	hit_targets[body] = true

	# Only authority deals damage
	if player_owner and not player_owner.is_multiplayer_authority():
		return

	var attacker_pos = player_owner.global_position if player_owner and is_instance_valid(player_owner) else global_position

	# Ignore other players
	if body.is_in_group("player") and body.has_method("take_damage"):
		return

	# Enemy: deal damage via game_world, spawn axe hit effect
	if body.is_in_group("enemy") and body.has_method("rpc_take_damage"):
		var game_world = get_tree().get_first_node_in_group("game_world")
		var enemy_name = body.name
		var enemy_index = body.get_meta("enemy_index") if body.has_meta("enemy_index") else -1
		if game_world and game_world.has_method("_request_enemy_damage"):
			if multiplayer.is_server():
				game_world._request_enemy_damage(enemy_name, enemy_index, damage, attacker_pos, false)
			else:
				game_world._request_enemy_damage.rpc_id(1, enemy_name, enemy_index, damage, attacker_pos, false)
		else:
			var eid = body.get_multiplayer_authority()
			if eid != 0:
				if multiplayer.is_server() and eid == multiplayer.get_unique_id():
					body.rpc_take_damage(damage, attacker_pos, false)
				else:
					body.rpc_take_damage.rpc_id(eid, damage, attacker_pos, false)
			else:
				body.rpc_take_damage.rpc(damage, attacker_pos, false)
		if has_node("MeleeImpact"):
			$MeleeImpact.play()
		_spawn_axe_hit_effect(body.global_position)
		return

	# Boxes / interactables with health
	if "health" in body:
		if has_node("MeleeImpact"):
			$MeleeImpact.play()
		body.health -= damage
		if body.health <= 0 and body.has_method("_break_into_pieces"):
			var game_world = get_tree().get_first_node_in_group("game_world")
			if game_world and multiplayer.has_multiplayer_peer():
				var obj_name = body.name
				if body.has_meta("object_index"):
					var idx = body.get_meta("object_index")
					if idx >= 0:
						obj_name = "InteractableObject_%d" % idx
				if multiplayer.is_server():
					game_world._rpc_to_ready_peers("_sync_object_break", [obj_name])
				else:
					game_world._sync_object_break.rpc_id(1, obj_name)
			body._break_into_pieces()
		_spawn_axe_hit_effect(body.global_position)
		return

	if has_node("MeleeImpactWall"):
		$MeleeImpactWall.play()

	# Knockback for CharacterBody2D (e.g. corpses)
	if body is CharacterBody2D:
		var knockback_dir = (body.global_position - global_position).normalized()
		body.velocity = knockback_dir * 200.0

func _spawn_axe_hit_effect(at_position: Vector2) -> void:
	if multiplayer.has_multiplayer_peer() and player_owner and player_owner.is_multiplayer_authority():
		var game_world = get_tree().get_first_node_in_group("game_world")
		if game_world and game_world.has_method("_sync_axe_hit_effect"):
			if multiplayer.is_server():
				game_world._sync_axe_hit_effect(at_position.x, at_position.y)
				if game_world.has_method("_rpc_to_ready_peers"):
					game_world._rpc_to_ready_peers("_sync_axe_hit_effect", [at_position.x, at_position.y])
			else:
				game_world._request_axe_hit_effect.rpc_id(1, at_position.x, at_position.y)
		return
	if not damage_effect_axe_scene:
		return
	var effect = damage_effect_axe_scene.instantiate()
	var parent = get_parent()
	if parent:
		parent.add_child(effect)
	else:
		get_tree().current_scene.add_child(effect)
	effect.global_position = at_position
	if effect.has_method("setup"):
		effect.setup(at_position)
