extends CharacterBody3D

signal attacked_player(damage: float)

@export var max_health: float = 20.0
@export var damage: float = 5.0
@export var detection_radius: float = 6.0
@export var attack_radius: float = 1.5
@export var move_speed: float = 1.0

enum State { WANDER, CHASE, ATTACK }

var health: float
var _state: State = State.WANDER
var _time: float = 0.0
var _wander_target: Vector3 = Vector3.ZERO
var _wander_timer: float = 0.0
var _attack_cooldown: float = 0.0
var _player: CharacterBody3D = null
var _base_scale: Vector3 = Vector3.ONE

# Visual nodes
var _dome: MeshInstance3D
var _tentacles: Array[MeshInstance3D] = []


func _ready() -> void:
	health = max_health
	_build_visuals()
	_find_player()
	_base_scale = scale
	_pick_wander_target()


func _find_player() -> void:
	var players := get_tree().get_nodes_in_group("player")
	if players.size() > 0:
		_player = players[0] as CharacterBody3D


func _build_visuals() -> void:
	var mat := StandardMaterial3D.new()
	mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
	mat.albedo_color = Color(0.9, 0.6, 0.9, 0.5)
	mat.emission_enabled = true
	mat.emission = Color(0.5, 0.1, 0.7)
	mat.emission_energy_multiplier = 0.8
	mat.cull_mode = BaseMaterial3D.CULL_DISABLED

	# Dome (sphere scaled to look like a bell)
	_dome = MeshInstance3D.new()
	var sphere := SphereMesh.new()
	sphere.radius = 0.5
	sphere.height = 0.7
	_dome.mesh = sphere
	_dome.material_override = mat
	_dome.scale = Vector3(1.0, 0.7, 1.0)
	add_child(_dome)

	# 4 tentacles
	var tent_mat := StandardMaterial3D.new()
	tent_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
	tent_mat.albedo_color = Color(0.85, 0.5, 0.85, 0.35)
	tent_mat.emission_enabled = true
	tent_mat.emission = Color(0.4, 0.0, 0.6)
	tent_mat.emission_energy_multiplier = 0.5
	tent_mat.cull_mode = BaseMaterial3D.CULL_DISABLED

	var offsets: Array[Vector2] = [
		Vector2(0.2, 0.0), Vector2(-0.2, 0.0),
		Vector2(0.0, 0.2), Vector2(0.0, -0.2)
	]
	for off: Vector2 in offsets:
		var tent := MeshInstance3D.new()
		var cap := CapsuleMesh.new()
		cap.radius = 0.04
		cap.height = 0.6
		tent.mesh = cap
		tent.material_override = tent_mat
		tent.position = Vector3(off.x, -0.55, off.y)
		add_child(tent)
		_tentacles.append(tent)

	# Collision shape
	var col := CollisionShape3D.new()
	var cshape := SphereShape3D.new()
	cshape.radius = 0.55
	col.shape = cshape
	add_child(col)


func _process(delta: float) -> void:
	_time += delta
	# Pulse animation
	var pulse: float = 1.0 + sin(_time * 3.0) * 0.08
	_dome.scale.y = 0.7 * pulse


func _physics_process(delta: float) -> void:
	if _player == null:
		_find_player()

	_attack_cooldown = max(0.0, _attack_cooldown - delta)
	_wander_timer = max(0.0, _wander_timer - delta)

	var player_dist: float = INF
	if is_instance_valid(_player):
		player_dist = global_position.distance_to(_player.global_position)

	match _state:
		State.WANDER:
			_do_wander(delta)
			if player_dist < detection_radius:
				_state = State.CHASE

		State.CHASE:
			if is_instance_valid(_player):
				var dir: Vector3 = (_player.global_position - global_position).normalized()
				velocity = dir * move_speed
				if player_dist < attack_radius:
					_state = State.ATTACK
			if player_dist > detection_radius * 1.5:
				_state = State.WANDER

		State.ATTACK:
			if is_instance_valid(_player) and _attack_cooldown <= 0.0:
				attacked_player.emit(damage)
				_attack_cooldown = 1.5
			if player_dist > attack_radius * 1.5:
				_state = State.CHASE

	# Smooth rotation toward movement
	if velocity.length_squared() > 0.01:
		var target_basis: Basis = Basis.looking_at(velocity.normalized(), Vector3.UP)
		transform.basis = transform.basis.slerp(target_basis, delta * 3.0)

	move_and_slide()


func _do_wander(delta: float) -> void:
	if _wander_timer <= 0.0:
		_pick_wander_target()

	var dir: Vector3 = (_wander_target - global_position)
	if dir.length() < 0.5:
		_pick_wander_target()
	else:
		velocity = dir.normalized() * move_speed * 0.5


func _pick_wander_target() -> void:
	_wander_target = global_position + Vector3(
		randf_range(-5.0, 5.0),
		randf_range(-2.0, 2.0),
		randf_range(-5.0, 5.0)
	)
	_wander_timer = randf_range(3.0, 6.0)


func take_damage(dmg: float) -> void:
	health -= dmg
	if health <= 0.0:
		queue_free()
