class_name ShotHUD extends Control
## HUD for main gameplay loop

## Scale factor for the life bar rumble intensity on taking damage
const LIFE_BAR_DAMAGE_RUMBLE_SCALE := 0.2
## Time it takes to dampen the life bar rumble on taking damage, in seconds
const LIFE_BAR_DAMAGE_RUMBLE_TIME := 0.2
## Time from restoring health to starting to fill the life bar, in seconds
const LIFE_BAR_HEAL_DELAY := 0.8
## Time it takes the life bar to fill when restoring life, in seconds
const LIFE_BAR_HEAL_TIME := 1.0

@export var nice_alert_scene: PackedScene

var player: WorldPlayer

var _aim_prompt_shown := false
var _power_prompt_shown := false
var _curve_prompt_shown := false
var _shot_prompt_shown := false
var _free_cam_prompts_shown := false

@onready var power_bar: TextureProgressBar = %PowerBar
@onready var curve_bar: CurveBar = %CurveBar

@onready var life_bar: TextureProgressBar = %LifeBar
@onready var life_particles: HUDParticles = %LifeParticles

@onready var club_selector: ClubSelector = %ClubSelector
@onready var ball_selector: BallSelector = %BallSelector
@onready var ball_particles: HUDParticles = %BallParticles

@onready var _curve_animation: AnimationPlayer = %CurveAnimation
@onready var _power_animation: AnimationPlayer = %PowerAnimation

@onready var _alert_container: Control = %AlertContainer
@onready var _wasted_animation: AnimationPlayer = %WastedAnimation

@onready var _club_selector_animation: AnimationPlayer = %ClubSelectorAnimation
@onready var _sw_animation: AnimationPlayer = %SWAnimation

@onready var _player_name: Label = %PlayerName

@onready var _reset_prompt_animation: AnimationPlayer = %ResetPromptAnimation
@onready var _aim_equip_prompt_animation: AnimationPlayer = %AimEquipPromptAnimation
@onready var _aim_prompt_animation: AnimationPlayer = %AimPromptAnimation
@onready var _power_prompt_animation: AnimationPlayer = %PowerPromptAnimation
@onready var _curve_prompt_animation: AnimationPlayer = %CurvePromptAnimation
@onready var _shot_prompt_animation: AnimationPlayer = %ShotPromptAnimation
@onready var _free_cam_util_prompt_animation: AnimationPlayer = %FreeCamUtilPromptAnimation
@onready var _free_cam_motion_prompt_animation: AnimationPlayer = %FreeCamMotionPromptAnimation

@onready var _life_bar_rumbler: Rumbler = %LifeBarRumbler

@onready var _heal_sfx: AudioStreamPlayer = %HealSFX

static var scene: PackedScene = preload("res://src/ui/shot_hud/shot_hud.tscn")


func _ready() -> void:
	club_selector.set_state_for_player(player)
	ball_selector.set_state_for_player(player)
	_player_name.text = player.name
	life_bar.value = player.life
	life_bar.tint_progress = player.color

	player.on_life_changed.connect(set_life_value)
	# TODO special equipment
	# TODO abilities


func show_hud() -> void:
	_club_selector_animation.play("show")
	_sw_animation.play("show")


func hide_hud() -> void:
	_club_selector_animation.play("hide")
	_sw_animation.play("hide")


func peek_club_selector() -> void:
	_club_selector_animation.play("peek")


func peek_life_bar() -> void:
	_sw_animation.play("peek")


func start_power_bar() -> void:
	_power_animation.play("fill")


func stop_power_bar() -> void:
	_power_animation.pause()


func reset_power_bar() -> void:
	_power_animation.stop()


func start_curve_bar() -> void:
	_curve_animation.play("fill")


func stop_curve_bar() -> void:
	_curve_animation.pause()


func reset_curve_bar() -> void:
	_curve_animation.stop()


func gauge_flourish() -> void:
	curve_bar.flourish()


func play_nice_animation() -> void:
	_alert_container.add_child(nice_alert_scene.instantiate())


func play_wasted_animation() -> void:
	_wasted_animation.play("display")


func show_reset_prompt() -> void:
	_reset_prompt_animation.play("show")


func hide_reset_prompt() -> void:
	_reset_prompt_animation.play_backwards("show")


func show_aim_prompt() -> void:
	if not _aim_prompt_shown:
		_aim_prompt_shown = true
		_aim_equip_prompt_animation.play("show")
		_aim_prompt_animation.play("show")


func hide_aim_prompt() -> void:
	if _aim_prompt_shown:
		_aim_prompt_shown = false
		_aim_equip_prompt_animation.play_backwards("show")
		_aim_prompt_animation.play_backwards("show")


func show_power_prompt() -> void:
	if not _power_prompt_shown:
		_power_prompt_shown = true
		_power_prompt_animation.play("show")


func hide_power_prompt() -> void:
	if _power_prompt_shown:
		_power_prompt_shown = false
		_power_prompt_animation.play_backwards("show")


func show_curve_prompt() -> void:
	if not _curve_prompt_shown:
		_curve_prompt_shown = true
		_curve_prompt_animation.play("show")


func hide_curve_prompt() -> void:
	if _curve_prompt_shown:
		_curve_prompt_shown = false
		_curve_prompt_animation.play_backwards("show")


func show_free_cam_prompts() -> void:
	if not _free_cam_prompts_shown:
		_free_cam_prompts_shown = true
		_free_cam_motion_prompt_animation.play("show")
		_free_cam_util_prompt_animation.play("show")


func hide_free_cam_prompts() -> void:
	if _free_cam_prompts_shown:
		_free_cam_prompts_shown = false
		_free_cam_motion_prompt_animation.play_backwards("show")
		_free_cam_util_prompt_animation.play_backwards("show")


func show_shot_prompt() -> void:
	if not _shot_prompt_shown:
		_shot_prompt_shown = true
		_shot_prompt_animation.play("show")


func hide_shot_prompt() -> void:
	if _shot_prompt_shown:
		_shot_prompt_shown = false
		_shot_prompt_animation.play_backwards("show")


func hide_idle_prompts() -> void:
	hide_aim_prompt()
	hide_power_prompt()
	hide_curve_prompt()
	hide_shot_prompt()


## Set the value of the life bar, potentially playing some kind of effect in response.
##
## To set the life bar without triggering an effect, set it directly with `life_bar.value`
func set_life_value(new_value: float) -> void:
	var difference := new_value - life_bar.value
	if difference < 0:
		# Taking damage
		peek_life_bar()
		_life_bar_rumbler.intensity = LIFE_BAR_DAMAGE_RUMBLE_SCALE * abs(difference)
		var tween := get_tree().create_tween()
		(
			tween
			. tween_property(_life_bar_rumbler, "intensity", 0, LIFE_BAR_DAMAGE_RUMBLE_TIME)
			. set_trans(Tween.TRANS_CUBIC)
		)
		life_bar.value = new_value
	elif difference > 0:
		# Restoring health
		var tween := get_tree().create_tween()
		tween.tween_interval(LIFE_BAR_HEAL_DELAY)
		tween.tween_callback(_heal_sfx.play)
		tween.tween_property(life_bar, "value", new_value, LIFE_BAR_HEAL_TIME).set_trans(
			Tween.TRANS_CUBIC
		)


static func create(_player: WorldPlayer) -> ShotHUD:
	var instance: ShotHUD = scene.instantiate()
	instance.player = _player

	return instance
