# Hurry Curry! - a game about cooking
# Copyright (C) 2025 Hurry Curry! contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, version 3 of the License only.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
extends Node3D
class_name Character

const DEFAULT_MAIN_MESH = preload("res://player/character/default/main.res")
const CUSTOMER_MAIN_MESH = preload("res://player/character/customer_body.res")

const WALK_ANIM_STRENGTH := 0.05
const WALK_ANIM_SPEED:= 15.0

const BOT_COLOR := Color(0.349, 0.349, 0.349)
const COLORS: Array[Color] = [
	Color(0.204, 0.361, 0.624),
	Color(0.568, 0.256, 0.602),
	Color(0.575, 0.341, 0.117),
	Color(0.3, 0.455, 0.221),
	Color(0.101, 0.452, 0.521)
]

var walking := false
var holding := false
var boosting := false
var cutting := false
var rolling := false
var was_boosting := boosting

var current_animation := "idle"

var hairstyles: Array[Mesh]= [
	preload("res://player/character/hairstyles/hair_1.res"),
	preload("res://player/character/hairstyles/hair_2.res"),
	preload("res://player/character/hairstyles/hair_3.res"),
	]

var headwears: Array[PackedScene]= [
	null,
	preload("res://player/character/headwear/cat_ears.tscn"),
	preload("res://player/character/headwear/propeller_hat.tscn"),
	preload("res://player/character/headwear/devil_horns.tscn"),
	]

@onready var headwear_parent: Node3D = $Main/HeadDefault/Headwear
@onready var hair_mesh: MeshInstance3D = $Main/HeadDefault/HairMesh

@onready var hand_animations = $HandAnimations
@onready var main = $Main
@onready var default_height = main.position.y
@onready var main_height_target = default_height
@onready var walking_particles = $Walking
@onready var boosting_particles = $Boosting
@onready var username_tag = $Username
@onready var tie = $Main/Tie
@onready var knife = $Main/HandRight/Knife
@onready var rolling_pin = $Main/RollingPin

@onready var head_default: MeshInstance3D = $Main/HeadDefault
@onready var head_robot: MeshInstance3D = $Main/HeadRobot

@onready var step_sounds: PlayRandom = $Steps
@onready var boost_sounds: PlayRandom = $Boosts

func _ready():
	play_animation("idle")

var t := 0.
func _process(delta):
	if walking:
		main_height_target = default_height + sin(t * WALK_ANIM_SPEED) * WALK_ANIM_STRENGTH
		t = fmod(t + delta, 2 * PI)
	else: t = 0.
	main.position.y = G.interpolate(main.position.y, main_height_target, delta * 25.)

	# Update animation:
	var next_animation: String
	if holding: next_animation = "hold"
	elif cutting: next_animation = "cut"
	elif rolling: next_animation = "roll"
	elif walking: next_animation = "walk"
	else: next_animation = "idle"
	
	if current_animation != next_animation:
		play_animation(next_animation)

	walking_particles.emitting = walking
	if boosting and walking and not was_boosting:
		boosting_particles.emitting = true
		boost_sounds.play_random()
	else:
		boosting_particles.emitting = false
	was_boosting = boosting and walking

func set_style(style: Dictionary, character_class: String):
	var hairstyle_idx := G.rem_euclid(style.hairstyle, hairstyles.size())
	var headwear_idx := G.rem_euclid(style.headwear, headwears.size())
	
	var is_human := character_class == "customer" || character_class == "chef"
	
	main.mesh = CUSTOMER_MAIN_MESH if character_class == "customer" else DEFAULT_MAIN_MESH
	tie.visible = character_class != "customer"
	head_robot.visible = character_class == "bot"
	head_default.visible = is_human
	
	# Hairstyle
	hair_mesh.mesh = hairstyles[hairstyle_idx]
	hair_mesh.visible = headwear_idx != 2
	
	# Headwear
	for n in headwear_parent.get_children():
		n.queue_free() # Remove previous headwear
	var headwear := headwears[headwear_idx]
	if headwear != null:
		headwear_parent.add_child(headwear.instantiate())
	
	# Torso color
	main.get_active_material(0).albedo_color = BOT_COLOR if character_class == "bot" else COLORS[G.rem_euclid(style.color, COLORS.size())]

func play_animation(name_: String):
	current_animation = name_
	hand_animations.play(name_)
	
	if name_ == "walk": step_sounds.start_autoplay()
	else: step_sounds.stop_autoplay()
	
	knife.visible = name_ == "cut"
	rolling_pin.visible = name_ == "roll"

func _on_hand_animations_animation_finished(_name):
	hand_animations.play(current_animation)
