extends "res://scripts/enemy_base.gd"

# Bat Enemy - Flies around, stationary when idle

enum BatState { IDLE, FLYING }
var state: BatState = BatState.IDLE
var state_timer: float = 0.0

var idle_duration: float = 2.0  # How long to stay idle
var fly_duration: float = 3.0   # How long to fly around
var detection_range: float = 80.0  # Range to detect players (much smaller)

var fly_height: float = 8.0  # Z position when flying

# Audio
@onready var bat_flap_sfx: AudioStreamPlayer2D = $BatFlapSfx
@onready var bat_chirp_sfx: AudioStreamPlayer2D = $BatChirpSfx
var has_played_chase_sound: bool = false  # Track if we've played sound when starting to chase

func _ready():
	super._ready()
	
	max_health = 18.0  # Reduced from 30.0 for better balance
	current_health = max_health
	move_speed = 40.0  # Reasonable speed for bats
	damage = 5.0
	exp_reward = 6.0  # Bats give low-moderate EXP
	
	state_timer = idle_duration
	
	# CRITICAL: Ensure collision mask is set correctly (walls are on layer 7 = bit 6 = 64)
	collision_mask = 1 | 2 | 64  # Collide with players (layer 1), objects (layer 2), and walls (layer 7 = bit 6 = 64)

# Override to set weak stats for bats
func _initialize_character_stats():
	super._initialize_character_stats()
	# Bats are weak enemies - very low END for low DEF
	character_stats.baseStats.end = 5  # END=5 gives DEF=1.0 (5 * 0.2)
	character_stats.baseStats.str = 5  # Low STR = low damage
	character_stats.baseStats.dex = 10  # Higher DEX (bats are agile)
	character_stats.baseStats.int = 5
	character_stats.baseStats.wis = 5
	character_stats.baseStats.lck = 5
	# Re-initialize hp and mp with new stats
	character_stats.hp = character_stats.maxhp
	character_stats.mp = character_stats.maxmp
	# Sync max_health from character_stats
	max_health = character_stats.maxhp
	current_health = max_health

func _physics_process(delta):
	# Always update animation (even when dead, and on clients)
	_update_animation(delta)
	
	# Always update Z position and shadow (even on clients)
	_update_z_position(delta)
	
	# Call parent physics process (handles dead state, authority checks, etc.)
	super._physics_process(delta)

func _ai_behavior(delta):
	# Update state timer
	state_timer -= delta
	
	# Find nearest player within detection range
	target_player = _find_nearest_player_in_range(detection_range)
	
	# State machine
	match state:
		BatState.IDLE:
			_idle_behavior(delta)
		BatState.FLYING:
			_flying_behavior(delta)
	
	# Animation and Z position are updated in _physics_process (always, even on clients)

func _idle_behavior(_delta):
	velocity = Vector2.ZERO
	position_z = 0.0
	
	# Show idle frame (frame 2)
	anim_frame = 2
	
	# Check if player is nearby
	if target_player:
		var dist = global_position.distance_to(target_player.global_position)
		if dist < detection_range:
			# Start flying (chasing player)
			var was_idle = (state == BatState.IDLE)
			state = BatState.FLYING
			state_timer = fly_duration
			
			# Play sound very seldom when starting to chase (only once per bat, with low chance)
			if was_idle and not has_played_chase_sound and randf() < 0.15:  # 15% chance
				_play_chase_sound()
				has_played_chase_sound = true
			return
	
	# Switch to flying after idle duration
	if state_timer <= 0:
		state = BatState.FLYING
		state_timer = fly_duration

func _flying_behavior(_delta):
	position_z = fly_height
	
	# Fly towards player if found
	if target_player and is_instance_valid(target_player):
		var direction = (target_player.global_position - global_position).normalized()
		velocity = direction * move_speed
		current_direction = _get_direction_from_vector(direction)
	else:
		# Wander randomly
		if randf() < 0.02:  # Small chance to change direction
			var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
			velocity = random_dir * move_speed
			current_direction = _get_direction_from_vector(random_dir)
	
	# Switch back to idle after flying duration
	if state_timer <= 0:
		state = BatState.IDLE
		state_timer = idle_duration

func _update_animation(delta):
	if state == BatState.IDLE:
		# Show idle frame
		anim_frame = 2
	else:
		# Animate flying (frames 0, 1, 2)
		anim_time += delta
		if anim_time >= anim_speed:
			anim_time = 0.0
			anim_frame = (anim_frame + 1) % 3
	
	# Map 8 directions to 4 sprite directions
	var sprite_dir = _get_sprite_direction()
	
	# Set sprite frame
	if sprite:
		sprite.frame = anim_frame + (sprite_dir * 3)  # 3 frames per direction

func _get_sprite_direction() -> int:
	# Map 8 directions to 4 sprite rows
	match current_direction:
		Direction.DOWN, Direction.DOWN_LEFT, Direction.DOWN_RIGHT:
			return 0  # Down row
		Direction.LEFT, Direction.UP_LEFT:
			return 1  # Left row
		Direction.RIGHT, Direction.UP_RIGHT:
			return 2  # Right row
		Direction.UP:
			return 3  # Up row
	return 0

func _update_z_position(_delta):
	# Update sprite Y offset based on height
	if sprite:
		sprite.position.y = -position_z * 0.5
	
	# Update shadow based on height (use same logic as base class _update_client_visuals for consistency)
	if shadow:
		var shadow_scale = 1.0 - (position_z / 50.0) * 0.5
		shadow.scale = Vector2.ONE * max(0.3, shadow_scale)
		shadow.modulate.a = 0.5 - (position_z / 50.0) * 0.2

func _update_client_visuals():
	# Update visuals on clients based on synced state
	super._update_client_visuals()
	
	# Update animation based on synced state
	_update_animation(0.0)  # Update animation immediately when state changes
	
	# Update sprite frame based on synced anim_frame and direction
	if sprite:
		var sprite_dir = _get_sprite_direction()
		sprite.frame = anim_frame + (sprite_dir * 3)  # 3 frames per direction

func _play_death_animation():
	# Fall to ground
	var fall_tween = create_tween()
	fall_tween.tween_property(self, "position_z", 0.0, 0.3)
	
	await fall_tween.finished
	
	# Fade out
	var fade_tween = create_tween()
	fade_tween.tween_property(sprite, "modulate:a", 0.0, 0.3)
	
	await fade_tween.finished
	queue_free()

func _play_chase_sound():
	# Play a random bat sound when starting to chase (very seldom)
	if not bat_flap_sfx and not bat_chirp_sfx:
		return
	
	# Randomly choose between flap or chirp
	if randf() < 0.5:
		if bat_flap_sfx and bat_flap_sfx.stream:
			bat_flap_sfx.play()
	else:
		if bat_chirp_sfx and bat_chirp_sfx.stream:
			bat_chirp_sfx.play()
