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

# Slime Enemy - Bounces around, can do minor jumps

enum SlimeState { IDLE, MOVING, JUMPING, DAMAGED, DYING }
var state: SlimeState = SlimeState.IDLE
var state_timer: float = 0.0

var idle_duration: float = 1.0
var move_duration: float = 2.0
var jump_chance: float = 0.3  # 30% chance to jump instead of walk
var detection_range: float = 70.0  # Range to detect players (much smaller)

# Jump mechanics
var is_jumping: bool = false

# Animation system (similar to player)
const ANIMATIONS = {
	"IDLE": {
		"frames": [0],
		"frameDurations": [500],
		"loop": true,
		"nextAnimation": null
	},
	"MOVE": {
		"frames": [0, 1, 2],
		"frameDurations": [200, 200, 200],
		"loop": true,
		"nextAnimation": null
	},
	"JUMP": {
		"frames": [2, 3, 4, 5, 7, 2],
		"frameDurations": [100, 100, 100, 100, 100, 100],
		"loop": false,
		"nextAnimation": "MOVE"
	},
	"DAMAGE": {
		"frames": [8, 9],
		"frameDurations": [150, 150],
		"loop": false,
		"nextAnimation": "IDLE"
	},
	"DIE": {
		"frames": [8, 9, 10, 11, 12, 13, 14],
		"frameDurations": [70, 70, 70, 70, 70, 70, 200],
		"loop": false,
		"nextAnimation": null
	}
}

var current_animation = "IDLE"
var current_frame = 0
var time_since_last_frame = 0.0

func _ready():
	super._ready()
	
	max_health = 12.0  # Reduced from 20.0 for better balance
	current_health = max_health
	move_speed = 20.0  # Very slow (reduced from 35)
	damage = 6.0
	exp_reward = 8.0  # Slimes give moderate EXP
	
	state_timer = idle_duration
	
	# CRITICAL: Ensure collision mask is set correctly after super._ready()
	# Walls are on layer 7 (bit 6 = 64), objects on layer 2, players on layer 1
	collision_mask = 1 | 2 | 64  # Collide with players (layer 1), objects (layer 2), and walls (layer 7 = bit 6 = 64)
	
	# Slime is small - adjust collision
	if collision_shape and collision_shape.shape:
		collision_shape.shape.radius = 6.0  # 12x12 effective size

# Override to set weak stats for slimes
func _initialize_character_stats():
	super._initialize_character_stats()
	# Slimes 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 = 6  # Low STR = low damage
	character_stats.baseStats.dex = 5  # Low DEX
	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)
	
	# 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:
		SlimeState.IDLE:
			_idle_behavior(delta)
		SlimeState.MOVING:
			_moving_behavior(delta)
		SlimeState.JUMPING:
			_jumping_behavior(delta)
		SlimeState.DAMAGED:
			_damaged_behavior(delta)
		SlimeState.DYING:
			return  # Do nothing while dying
	
	# Animation is updated in _physics_process (always, even on clients)

func _idle_behavior(_delta):
	velocity = Vector2.ZERO
	_set_animation("IDLE")
	
	# Check if player is nearby
	if target_player:
		var dist = global_position.distance_to(target_player.global_position)
		if dist < detection_range:
			# Start moving or jumping
			if randf() < jump_chance:
				_start_jump()
			else:
				state = SlimeState.MOVING
				state_timer = move_duration
			return
	
	# Switch to moving/jumping after idle duration
	if state_timer <= 0:
		if randf() < jump_chance:
			_start_jump()
		else:
			state = SlimeState.MOVING
			state_timer = move_duration

func _moving_behavior(_delta):
	_set_animation("MOVE")
	
	# Move slowly towards player
	if target_player and is_instance_valid(target_player):
		var direction = (target_player.global_position - global_position).normalized()
		velocity = direction * move_speed
	else:
		# Wander randomly
		if randf() < 0.02:
			var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
			velocity = random_dir * move_speed
	
	# Randomly jump while moving
	if state_timer > 0.5 and randf() < 0.01:
		_start_jump()
		return
	
	# Switch back to idle after move duration
	if state_timer <= 0:
		state = SlimeState.IDLE
		state_timer = idle_duration

func _start_jump():
	state = SlimeState.JUMPING
	is_jumping = true
	state_timer = 0.6  # Jump duration
	_set_animation("JUMP")
	
	# Jump towards player if nearby
	if target_player and is_instance_valid(target_player):
		var direction = (target_player.global_position - global_position).normalized()
		velocity = direction * (move_speed * 1.4)  # Slightly faster during jump (reduced from 1.8)
	else:
		# Random jump direction
		var random_dir = Vector2(randf() - 0.5, randf() - 0.5).normalized()
		velocity = random_dir * (move_speed * 1.4)  # Slightly faster during jump (reduced from 1.8)

func _jumping_behavior(_delta):
	# Continue moving in jump direction
	# Animation is handled in _update_animation
	
	# End jump
	if state_timer <= 0:
		is_jumping = false
		state = SlimeState.MOVING
		state_timer = move_duration

func _damaged_behavior(_delta):
	velocity = Vector2.ZERO
	_set_animation("DAMAGE")
	
	# Stay in damaged state briefly
	if state_timer <= 0:
		state = SlimeState.IDLE
		state_timer = idle_duration

func _set_animation(anim_name: String):
	# Validate animation exists before setting it
	if anim_name in ANIMATIONS:
		if current_animation != anim_name:
			current_animation = anim_name
			current_frame = 0
			time_since_last_frame = 0.0
	else:
		# Invalid animation name - fall back to IDLE
		print("EnemySlime: Invalid animation '", anim_name, "' - falling back to IDLE")
		if current_animation != "IDLE":
			current_animation = "IDLE"
			current_frame = 0
			time_since_last_frame = 0.0

func _update_animation(delta):
	# Safety check: ensure current_animation exists in ANIMATIONS
	if not current_animation in ANIMATIONS:
		print("EnemySlime: ERROR - current_animation '", current_animation, "' not in ANIMATIONS! Resetting to IDLE")
		current_animation = "IDLE"
		current_frame = 0
		time_since_last_frame = 0.0
		return
	
	# Update animation frame timing
	time_since_last_frame += delta
	if time_since_last_frame >= ANIMATIONS[current_animation]["frameDurations"][current_frame] / 1000.0:
		current_frame += 1
		if current_frame >= len(ANIMATIONS[current_animation]["frames"]):
			current_frame -= 1 # Prevent out of bounds
			if ANIMATIONS[current_animation]["loop"]:
				current_frame = 0
			elif ANIMATIONS[current_animation]["nextAnimation"] != null:
				current_frame = 0
				current_animation = ANIMATIONS[current_animation]["nextAnimation"]
		time_since_last_frame = 0.0
	
	# Calculate frame index
	var frame_index = ANIMATIONS[current_animation]["frames"][current_frame]
	
	# Set sprite frame (slime looks same in all directions)
	if sprite:
		sprite.frame = frame_index
	anim_frame = frame_index  # Keep anim_frame updated for compatibility

func _on_take_damage(_attacker_position: Vector2 = Vector2.ZERO):
	# Play damage animation
	state = SlimeState.DAMAGED
	state_timer = 0.3
	_set_animation("DAMAGE")

func _die():
	if is_dead:
		return
	
	# Remove collision layer so they don't collide with players, but still collide with walls
	set_collision_layer_value(2, false)  # Remove from enemy collision layer (layer 2)
	
	# Set state before calling parent _die()
	state = SlimeState.DYING
	velocity = Vector2.ZERO
	_set_animation("DIE")
	
	# Call parent _die() which handles death sync and _play_death_animation()
	super._die()

func _update_client_visuals():
	# Update visuals on clients based on synced state
	super._update_client_visuals()
	
	# CRITICAL: If dead, always show DIE animation (don't let state override it)
	# This prevents DAMAGED state from showing DAMAGE animation after death sync
	if is_dead:
		_set_animation("DIE")
		_update_animation(0.0)
		if sprite:
			sprite.frame = anim_frame
		return
	
	# Map synced state to animation (similar to how bat/rat use state directly)
	match state:
		SlimeState.IDLE:
			_set_animation("IDLE")
		SlimeState.MOVING:
			_set_animation("MOVE")
		SlimeState.JUMPING:
			_set_animation("JUMP")
		SlimeState.DAMAGED:
			_set_animation("DAMAGE")
		SlimeState.DYING:
			_set_animation("DIE")
	
	# Update animation based on synced state
	_update_animation(0.0)  # Update animation immediately when state changes
	
	# Update sprite frame (slime looks same in all directions, no direction mapping)
	if sprite:
		sprite.frame = anim_frame

func _play_death_animation():
	_set_animation("DIE")
	
	# Wait for death animation to complete
	var total_duration = 0.0
	for duration in ANIMATIONS["DIE"]["frameDurations"]:
		total_duration += duration / 1000.0
	await get_tree().create_timer(total_duration).timeout
	
	# Fade out
	if sprite:
		var fade_tween = create_tween()
		fade_tween.tween_property(sprite, "modulate:a", 0.0, 0.3)
		await fade_tween.finished
	
	queue_free()
