@tool
extends Node
class_name GameManager

@export_category("Complete rosters")
@export var character_roster: Array[CharacterResource]
@export var face_mask_roster: Array[MaskResource]
@export var mouth_mask_roster: Array[MaskResource]

@export_category("References")
@export var character: Character
@export var guest_list: List
@export var mask_list: List

@export_category("Tables")
@export var tables: Array[Table]

@export_category("Predetermined levels")
@export_group("Level 1")
@export var lvl1_guest_1: MaskedChara
@export var lvl1_guest_2: MaskedChara

@export_group("Level 2")
@export var lvl2_guest_1: MaskedChara
@export var lvl2_guest_2: MaskedChara

@export_group("Level 3")
@export var lvl3_guest_1: MaskedChara
@export var lvl3_guest_2: MaskedChara
@export var lvl3_guest_3: MaskedChara

@export_category("Random levels")
@export var current_level: Levels = Levels.LVL1
@export var max_number_guests: int = 9
@export var no_mask_probability: float = 0.2
@export var dual_mask_probability: float = 0.2
@export_tool_button("Create chara roster") var create_roster_action = create_new_roster

signal ring_bell_noise
signal victory_noise
signal defeat_noise 

var current_chara_roster: Array[MaskedChara]

enum GameState {
	READY,
	GUEST_REVIEW,
	FINISHED
}
enum Levels {
	LVL1,
	LVL2,
	LVL3,
	RANDOM
}
var current_game_state = GameState.READY
var first_guest = true
var current_guest: MaskedChara
var selected_seat: Seat
var roster_size: int = 2

@onready var camera_2d: Camera2D = $"../Camera2D"
@onready var ring_bell: Sprite2D = $"../RingBell"
@onready var bell_anim_player: AnimationPlayer = $"../RingBell/AnimationPlayer"


func create_new_roster() -> void:
	current_chara_roster = []
	var roster_for_this_round = character_roster.duplicate()
	var max_number_of_people = min(roster_size, character_roster.size(), max_number_guests)
	for i in range(max_number_of_people):
		# Pick unique characters for the roster
		var random_index = randi_range(0, roster_for_this_round.size() - 1)
		var chara: CharacterResource = roster_for_this_round.pop_at(random_index)
		
		var mouth_mask: MaskResource
		var eyes_mask: MaskResource
		var no_masked = randf() <= no_mask_probability
		if (no_masked):
			current_chara_roster.append(MaskedChara.new(chara, eyes_mask, mouth_mask))
			continue
		
		var should_pick_eye_mask = randi_range(0, 1) == 1
		var dual_masked = randf() <= dual_mask_probability
		if (should_pick_eye_mask):
			eyes_mask = face_mask_roster.pick_random()
			if dual_masked:
				mouth_mask = mouth_mask_roster.pick_random()
		else:
			mouth_mask = mouth_mask_roster.pick_random()
			if dual_masked:
				eyes_mask = face_mask_roster.pick_random()
		
		var masked_chara = MaskedChara.new(chara, eyes_mask, mouth_mask)

		current_chara_roster.append(masked_chara)
	
func review_next_guest():
	# See previous guest out
	if not first_guest:
		character.go_out()
		var timer = get_tree().create_timer(2)
		await timer.timeout
	
	# Check if we have more guests, if not we go to the ending
	current_guest = current_chara_roster.pop_front()
	if current_guest == null:
		current_game_state = GameState.FINISHED
		compute_ending()
		return
	
	# Process next guest
	character.chara_resource = current_guest.character
	character.mask_eyes.mask_resource = current_guest.face_mask
	character.mask_mouth.mask_resource = current_guest.mouth_mask
	
	first_guest = false
	character.come_in()

func compute_ending():
	var camera_tween = get_tree().create_tween()
	camera_tween.set_ease(Tween.EASE_IN_OUT)
	camera_tween.set_trans(Tween.TRANS_CUBIC)
	camera_tween.tween_property(camera_2d, "position", Vector2(2720.0, 0), 1.0)
	camera_tween.tween_callback(ending_tween_cb)
	
func ending_tween_cb():
	var final_score = 0.0
	var table1_score = tables[0].compute_score()
	var table2_score = tables[1].compute_score()
	var table3_score = tables[2].compute_score()
	final_score = table1_score + table2_score + table3_score
		
	print("Final score: %s" % final_score)
	var is_defeat = table1_score < 0 or table2_score < 0 or table3_score < 0
	if is_defeat:
		defeat_noise.emit()
	else:
		victory_noise.emit()
		
	await get_tree().create_timer(4).timeout
	
	var camera_tween = get_tree().create_tween()
	camera_tween.set_ease(Tween.EASE_IN_OUT)
	camera_tween.set_trans(Tween.TRANS_CUBIC)
	camera_tween.tween_property(camera_2d, "position", Vector2.ZERO, 0.5)
	await get_tree().create_timer(0.5).timeout
	
	# Progress levels
	current_game_state = GameState.READY
	ring_bell.visible = true
	bell_anim_player.play("idle")
	
	if is_defeat:
		return
		
	if current_level == Levels.LVL1:
		current_level = Levels.LVL2
	elif current_level == Levels.LVL2:
		current_level = Levels.LVL3
	else:
		roster_size += 1
		current_level = Levels.RANDOM
	

func _ready() -> void:
	character.visible = false


func _on_ready_bell_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void:
	if event is InputEventMouseButton and event.is_pressed():
		ring_bell_noise.emit()
		if current_game_state == GameState.READY:
			on_ready_bell_pressed()

func on_ready_bell_pressed() -> void:
	if(current_game_state != GameState.READY):
		return
	
	for table in tables:
		table.initialize()
	
	guest_list.visible = true
	if current_level == Levels.LVL1:
		current_chara_roster = [lvl1_guest_1, lvl1_guest_2]
	elif current_level == Levels.LVL2:
		current_chara_roster = [lvl2_guest_1, lvl2_guest_2]
		mask_list.visible = true
	elif current_level == Levels.LVL3:
		current_chara_roster = [lvl3_guest_1, lvl3_guest_2, lvl3_guest_3]
	else:
		create_new_roster()
	
	var all_chara_in_current_roster: Array[CharacterResource] = []
	var all_masks_in_current_roster: Array[MaskResource] = []
	for masked_chara in current_chara_roster:
		all_chara_in_current_roster.append(masked_chara.character)
		if masked_chara.face_mask != null:
			all_masks_in_current_roster.append(masked_chara.face_mask)
		if masked_chara.mouth_mask != null:
			all_masks_in_current_roster.append(masked_chara.mouth_mask)
		
	mask_list.set_list(all_masks_in_current_roster)
	guest_list.set_list(all_chara_in_current_roster)
	
	current_game_state = GameState.GUEST_REVIEW
	bell_anim_player.stop()
	ring_bell.visible = false
	first_guest = true
	review_next_guest()


func on_seat_clicked(seat: Seat) -> void:
	if current_guest == null and not current_game_state == GameState.GUEST_REVIEW:
		return
		
	selected_seat = seat
	var camera_tween = get_tree().create_tween()
	camera_tween.set_ease(Tween.EASE_IN_OUT)
	camera_tween.set_trans(Tween.TRANS_CUBIC)
	camera_tween.tween_property(camera_2d, "position", Vector2.ZERO, 1.0)
	camera_tween.tween_callback(camera_tween_cb)
	
func camera_tween_cb() -> void:
	selected_seat.set_guest(current_guest)
	review_next_guest()
