extends Node2D

# Flame Spell - Spawns at target position and deals damage over time

@export var damage: float = 15.0
@export var damage_interval: float = 0.5  # Deal damage every 0.5 seconds
@export var lifetime: float = 2.0  # Spell lasts 2 seconds

var player_owner: Node = null
var hit_targets = {}  # Track what we've already hit
var first_hit_targets = {}  # Track targets that haven't taken initial damage yet
var bodies_in_area = {}  # Track bodies currently in the area (for enter/exit detection)
var damage_timer: float = 0.0
var animation_timer: float = 0.0
var current_frame: int = 4  # Start at frame 4 (first burning frame)
var is_fading_out: bool = false  # True when playing fade-out frames (2, 1, 0)
var fade_out_frame_index: int = 0  # Index into fade-out frames [2, 1, 0]
var initial_damage_window: float = 0.2  # Initial 0.2 seconds for bonus damage
var initial_damage_multiplier: float = 3.0  # Initial damage is 3x base damage
var spell_start_time: float = 0.0  # Time when spell started
var explosion_init_frame: int = 0  # Current frame of explosion init animation
var explosion_init_timer: float = 0.0  # Timer for explosion init animation

@onready var sprite = $Sprite2D
@onready var explosion_init_sprite = $ExplosionInit
@onready var hit_area = $Area2D
@onready var lifetime_timer = $LifetimeTimer

func _ready():
	# Connect area signals
	if hit_area and not hit_area.body_entered.is_connected(_on_body_entered):
		hit_area.body_entered.connect(_on_body_entered)
	
	# Start lifetime timer
	lifetime_timer.wait_time = lifetime
	lifetime_timer.timeout.connect(_on_lifetime_expired)
	lifetime_timer.start()
	
	# Track spell start time
	spell_start_time = Time.get_ticks_msec() / 1000.0
	
	# Show explosion init animation first
	if explosion_init_sprite:
		explosion_init_sprite.visible = true
		explosion_init_sprite.frame = 0
		explosion_init_frame = 0
		explosion_init_timer = 0.0
	
	# Hide main sprite during explosion init
	if sprite:
		sprite.visible = false
	
	# Play sounds
	if has_node("SfxInit"):
		$SfxInit.play()
	if has_node("SfxFire"):
		$SfxFire.play()

func setup(target_position: Vector2, owner_player: Node, damage_value: float = 15.0):
	global_position = target_position
	player_owner = owner_player
	damage = damage_value

func _process(delta):
	damage_timer += delta
	animation_timer += delta
	explosion_init_timer += delta
	
	# Handle explosion init animation (4 frames, then hide)
	if explosion_init_sprite and explosion_init_sprite.visible:
		# Play 4 frames of explosion init (0, 1, 2, 3) at ~30 FPS
		if explosion_init_timer >= 0.1:
			explosion_init_timer = 0.0
			explosion_init_frame += 1
			if explosion_init_frame < 4:
				explosion_init_sprite.frame = explosion_init_frame
			else:
				# Hide explosion init and show main sprite
				explosion_init_sprite.visible = false
				if sprite:
					sprite.visible = true
					_start_sprite_animation()
	
	# Check if spell is about to expire (last 0.5 seconds)
	var time_remaining = lifetime_timer.time_left
	var fade_out_start_time = 0.5  # Start fade-out 0.5 seconds before expiration
	
	if not is_fading_out and time_remaining <= fade_out_start_time:
		# Start fade-out sequence
		is_fading_out = true
		fade_out_frame_index = 0
		animation_timer = 0.0
		# Fade-out frames: 2, 1, 0
		var fade_out_frames = [2, 1, 0]
		current_frame = fade_out_frames[0]
		if sprite:
			sprite.frame = current_frame
	
	# Animate sprite frames (only if explosion init is done)
	if sprite and sprite.visible:
		if is_fading_out:
			# Play fade-out frames (2, 1, 0) - slower transition (0.15s per frame)
			if animation_timer >= 0.15:  # Slower for fade-out
				animation_timer = 0.0
				var fade_out_frames = [2, 1, 0]
				fade_out_frame_index += 1
				if fade_out_frame_index < fade_out_frames.size():
					current_frame = fade_out_frames[fade_out_frame_index]
					sprite.frame = current_frame
				# If we've played all fade-out frames, keep on frame 0 until expiration
				elif fade_out_frame_index >= fade_out_frames.size():
					current_frame = 0
					sprite.frame = 0
		else:
			# Normal animation: cycle through frames 4-15 (~30 FPS)
			if animation_timer >= 0.03333333:
				animation_timer = 0.0
				current_frame += 1
				if current_frame > 15:
					current_frame = 4  # Loop back to first burning frame
				sprite.frame = current_frame
	
	# Deal periodic damage to targets in area (only if not fading out and explosion init is done)
	if sprite and sprite.visible and not is_fading_out and damage_timer >= damage_interval:
		damage_timer = 0.0
		_deal_periodic_damage()

func _start_sprite_animation():
	# Initialize sprite to first burning frame
	if sprite:
		sprite.frame = 4  # First frame of burning animation
		current_frame = 4

func _deal_periodic_damage():
	# Get all bodies in the area
	var bodies = hit_area.get_overlapping_bodies()
	var current_bodies = {}
	
	for body in bodies:
		if body == player_owner:
			continue
		
		# CRITICAL: Only the spell owner (authority) should deal damage
		if player_owner and not player_owner.is_multiplayer_authority():
			continue
		
		current_bodies[body] = true
		
		# Check if this body just entered the area (not in bodies_in_area)
		var just_entered = not (body in bodies_in_area)
		
		# If body just entered, deal high damage (like initial hit)
		# Also deal high damage on first hit ever
		var is_first_hit = not (body in first_hit_targets)
		if is_first_hit:
			first_hit_targets[body] = true
		
		# Calculate damage - high damage when entering area or first hit, regular damage otherwise
		var final_damage = damage
		var int_bonus_damage = 0.0  # Declare outside if block for use in print statements
		if just_entered or is_first_hit:
			# High damage when entering area (multiplied and gets INT bonus)
			final_damage = damage * initial_damage_multiplier
			if player_owner and player_owner.character_stats:
				var int_stat = player_owner.character_stats.baseStats.int + player_owner.character_stats.get_pass("int")
				int_bonus_damage = int_stat * 0.5  # 0.5 damage per INT point
				final_damage += int_bonus_damage
		
		# Deal damage to players
		if body.is_in_group("player") and body.has_method("rpc_take_damage"):
			var attacker_pos = player_owner.global_position if player_owner else global_position
			var player_peer_id = body.get_multiplayer_authority()
			
			# Apply burn debuff with 50% chance
			var apply_burn = randf() < 0.5
			
			if player_peer_id != 0:
				if multiplayer.is_server() and player_peer_id == multiplayer.get_unique_id():
					body.rpc_take_damage(final_damage, attacker_pos, false, apply_burn)  # Pass burn flag
				else:
					body.rpc_take_damage.rpc_id(player_peer_id, final_damage, attacker_pos, false, apply_burn)
			else:
				body.rpc_take_damage.rpc(final_damage, attacker_pos, false, apply_burn)
			
			if is_first_hit:
				var int_bonus = int_bonus_damage if player_owner and player_owner.character_stats else 0.0
				print("Flame spell INITIAL hit player: ", body.name, " for ", final_damage, " damage (base: ", damage, " x ", initial_damage_multiplier, " + INT bonus: ", int_bonus, ")")
			else:
				print("Flame spell hit player: ", body.name, " for ", final_damage, " damage!")
		
		# Deal damage to enemies
		elif 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
			
			# Apply burn debuff with 50% chance
			var apply_burn = randf() < 0.5
			
			# Use game_world's _request_enemy_damage for damage, but we need to handle burn separately
			# Since _request_enemy_damage doesn't support burn, we'll call rpc_take_damage directly
			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(final_damage, attacker_pos, false, false, apply_burn)  # is_critical=false, is_burn_damage=false, apply_burn_debuff
				else:
					body.rpc_take_damage.rpc_id(enemy_peer_id, final_damage, attacker_pos, false, false, apply_burn)
			else:
				body.rpc_take_damage.rpc(final_damage, attacker_pos, false, false, apply_burn)
			
			if just_entered or is_first_hit:
				var int_bonus = int_bonus_damage if player_owner and player_owner.character_stats else 0.0
				print("Flame spell HIGH DAMAGE hit enemy: ", body.name, " for ", final_damage, " damage (base: ", damage, " x ", initial_damage_multiplier, " + INT bonus: ", int_bonus, ")")
			else:
				print("Flame spell hit enemy: ", body.name, " for ", final_damage, " damage!")
		
		# Destroy wooden interactable objects (box, barrel, pot, etc.) – they burn and break
		elif body.is_in_group("interactable_object") and body.has_method("take_fire_damage"):
			if "is_being_held" in body and body.is_being_held:
				continue  # Don't break objects while held
			var attacker_pos = player_owner.global_position if player_owner else global_position
			body.take_fire_damage(final_damage, attacker_pos)
			if just_entered or is_first_hit:
				print("Flame spell HIGH DAMAGE burning wooden object: ", body.name, " for ", final_damage, " damage!")
			else:
				print("Flame spell burning wooden object: ", body.name, " for ", final_damage, " damage!")
	
	# Update bodies_in_area for next check
	bodies_in_area = current_bodies

func _on_body_entered(body):
	# Track bodies that enter the area - they will get high damage on next periodic check
	# The _deal_periodic_damage function will detect they just entered and deal high damage
	if body and body != player_owner:
		# Mark that this body just entered (will be processed in _deal_periodic_damage)
		pass

func _on_lifetime_expired():
	# Spell expires - fade out and remove
	hit_area.set_deferred("monitoring", false)
	queue_free()
