# 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/>.
#
class_name Item
extends Node3D

const CHECKMARK: PackedScene = preload("uid://bdbw8whs3data")

var item_name #: String

var owned_by: Node3D
var base: Node3D = Node3D.new()
var rotation_target: float = 0.
var position_target: Vector3 = Vector3(0., 0., 0.)
var height: float = 0.1

var progress_instance: Progress3D = preload("res://map/progress/progress.tscn").instantiate()
var take_sound: PlayRandom = preload("res://audio/play_random.tscn").instantiate()
var put_sound: PlayRandom = preload("res://audio/play_random.tscn").instantiate()
var beep_sound := AudioStreamPlayer3D.new()
var sound_id

var progress_speed := 0.
var progress_position := 0.
var progress_warn := false

var destroy_timeout = null
var creation_timer = null
var item_owned = false
var player_owned_timer = 0.0

func _init(owned_by_: Node3D):
	progress_instance.position.y = 1
	progress_instance.visible = false
	add_child(progress_instance)
	take_sound.volume_db = -16
	put_sound.volume_db = -16
	add_child(take_sound)
	add_child(put_sound)
	beep_sound.stream = preload("res://map/tiles/sounds/beep.ogg")
	add_child(beep_sound)
	setup_sounds()
	@warning_ignore("static_called_on_instance")
	base.position = base_position()
	base.name = "Base"
	add_child(base)
	owned_by = owned_by_

func is_round(): return true

func add_contents(contents: Array[String]):
	for i in contents:
		match i:
			_:
				base.add_child(ItemFactory.produce(i, self))

func animate_spawn():
	creation_timer = 0.0
	scale = Vector3.ONE * 0.001 # setting to zero breaks assertions somewhere in the engine

func _process(delta):
	if not is_instance_valid(owned_by): return
	if owned_by.get_parent() is Item or owned_by is Item: return
	var player_owned = owned_by.get_parent().get_parent() is Player
	player_owned_timer = player_owned_timer + delta if player_owned else 0.
	var anim_speed = 10.0 * exp(player_owned_timer * 3.0) # infinity is fine. G.interpolate can handle it
	position = G.interpolate(position, position_target, delta * anim_speed)
	rotation.y = G.interpolate_angle(rotation.y, rotation_target, delta * anim_speed)
	if creation_timer != null:
		creation_timer += delta * 10.0
		if creation_timer > 1:
			scale = Vector3.ONE
			creation_timer = null
		else: scale = Vector3.ONE * creation_timer
	if destroy_timeout != null:
		destroy_timeout -= delta * 5.0
		if is_instance_valid(progress_instance): progress_instance.hide()
		if destroy_timeout <= 0: queue_free()
		else: scale = Vector3.ONE * destroy_timeout

	if !Global.game_paused:
		progress_position += delta * progress_speed
		progress_instance.update(progress_position, progress_warn)
		var time_remaining = (1 - progress_position) / progress_speed

		if progress_warn and progress_speed > 0 and time_remaining < 5.:
			if not beep_sound.playing:
				beep_sound.play()
		else: beep_sound.stop()
	else: beep_sound.stop()

func progress(position_: float, speed: float, warn: bool):
	progress_instance.visible = true
	progress_position = position_
	progress_speed = speed
	progress_warn = warn

	if position_ == 1.0:
		# Progress gets called with position 1.0 when the task is finished
		if not warn:
			# Task finished succesfully
			var checkmark: CPUParticles3D = CHECKMARK.instantiate()
			owned_by.add_child(checkmark)
			checkmark.position.y = 0.5
			checkmark.emitting = true
			
			var ding_sound := AudioStreamPlayer3D.new()
			owned_by.add_child(ding_sound)
			ding_sound.stream = preload("res://map/tiles/sounds/ding.ogg")
			ding_sound.play()
		else:
			# Task failed, food burned
			var burn_sound := AudioStreamPlayer3D.new()
			owned_by.add_child(burn_sound)
			burn_sound.stream = preload("res://map/tiles/sounds/burn.ogg")
			burn_sound.volume_db = -2
			burn_sound.play()

func finish():
	progress_instance.visible = false
	if sound_id != null:
		Sound.item_finished(sound_id)

func setup_sounds():
	take_sound.setup([preload("res://map/items/sounds/generic_take.ogg")])
	put_sound.setup([preload("res://map/items/sounds/plate_put.ogg")])

func remove():
	destroy_timeout = 1

func take():
	take_sound.play_random()

func put():
	put_sound.play_random()

static func base_position() -> Vector3:
	return Vector3(0., 0., 0.)
