class_name Player
extends Node2D

signal draft_completed
signal board_attached

enum DraftType {STARTING_HAND, HIRE_WORKER}

@export var fsm : StateMachine
@export var roster_positions : Array[Node2D] = []
@export var slot_buttons : Array[Node2D] = []
@export var hand_slide_anim_time := 0.3
var money := 0
var payout := 0
var cost := 0
var hire_costs := [40, 50, 60, 70, 80]
var shift_deck : Array[Client] = []
var workers : Array[Worker] = []
var hand : Array[Worker] = []
var active_workers : Array[Worker] = [null, null, null, null, null]
var active_clients : Array[Client] = [null, null, null, null, null]
var poor_discard : Array[Client] = []
var good_discard : Array[Client] = []
var great_discard : Array[Client] = []
var draft := DraftType.HIRE_WORKER
var hand_hiding := false
var hand_hidden := false
var hand_hiding_progress := 0.0
var hand_showing := false
var hand_showing_progress := 0.0
var shown_for_draft : Array[Worker] = []
var selected_for_draft : Array[Worker] = []
var draft_limit := 0
var current_client : Client
var selected_worker : Worker
var task_drawn := false
var client_assignment : int = -1
var board : Board = null
var turn_completed = false
var round_completed = false

@onready var pile_draw = $TaskDrawDeck/Area2D/CollisionShape2D
@onready var pile_poor = $PoorDiscardPile/Area2D/CollisionShape2D

@onready var clients_left = $TaskDrawDeck/Count

@onready var camera = $Camera2D


func _ready() -> void:
	#Bug in Godot 4.0.3.stable makes it nessesary to add these manually
	roster_positions.append($RosterSection/Position1)
	roster_positions.append($RosterSection/Position2)
	roster_positions.append($RosterSection/Position3)
	roster_positions.append($RosterSection/Position4)
	roster_positions.append($RosterSection/Position5)
	roster_positions.append($RosterSection/Position6)
	roster_positions.append($RosterSection/Position7)
	roster_positions.append($RosterSection/Position8)
	roster_positions.append($RosterSection/Position9)
	roster_positions.append($RosterSection/Position10)
	roster_positions.append($RosterSection/Position11)
	roster_positions.append($RosterSection/Position12)
	roster_positions.append($RosterSection/Position13)
	roster_positions.append($RosterSection/Position14)
	roster_positions.append($RosterSection/Position15)
	slot_buttons.append($StateMachine/Worker/WorkerPlaySlots/Slot1)
	slot_buttons.append($StateMachine/Worker/WorkerPlaySlots/Slot2)
	slot_buttons.append($StateMachine/Worker/WorkerPlaySlots/Slot3)
	slot_buttons.append($StateMachine/Worker/WorkerPlaySlots/Slot4)
	slot_buttons.append($StateMachine/Worker/WorkerPlaySlots/Slot5)
	for button in slot_buttons:
		button.button_pushed.connect(select_slot)
	$PoorDiscardPile/Label.text = "No / Poor service"
	$GoodDiscardPile/Label.text = "Good service"
	$GreatDiscardPile/Label.text = "Great service"
	$TaskDrawDeck/Label.text = "Click to draw task card"
	$Camera2D.make_current()
	await board_attached
	fsm.change_state(fsm.FSMState.SETUP)


func _process(delta) -> void:
	if (hand_hiding):
		if hand_hiding_progress < hand_slide_anim_time:
			hand_hiding_progress += delta
			var percent = clampf(hand_hiding_progress / hand_slide_anim_time, 0.0, 1.0)
			for card in hand:
				card.hand_position.y = lerpf($Hand.position.y, $Hand.position.y + 300.0, percent)
		else:
			hand_hiding = false
			hand_hidden = true
			hand_hiding_progress = 0.0
	if (hand_showing):
		if hand_showing_progress < hand_slide_anim_time:
			hand_showing_progress += delta
			var percent = clampf(hand_showing_progress / hand_slide_anim_time, 0.0, 1.0)
			for card in hand:
				card.hand_position.y = lerpf($Hand.position.y + 300.0, $Hand.position.y, percent)
		else:
			hand_showing = false
			hand_showing_progress = 0.0


func start_turn():
	pass


func start_round():
	pass


@rpc("call_local")
func attach_board(board_path : NodePath):
	board = get_node(board_path) as Board
	board_attached.emit()


func add_to_hand(card):
	hand.append(card)
	for x in hand.size():
		var hand_ratio = 0.5
		
		if hand.size() > 1:
			hand_ratio = float(x) / float(hand.size() - 1)
		hand[x].position = $Hand.position
		hand[x].hand_ratio = hand_ratio
		hand[x].in_hand = true
		hand[x].hand_position = $Hand.position
		hand[x].visible = true
		hand[x].set_process(true)


func lift_hand():
	for card in hand:
		card.hovered = true


func drop_hand():
	for card in hand:
		card.hovered = false


func select_card(card):
	if fsm.state == fsm.FSMState.DRAFT:
		if selected_for_draft.size() <= draft_limit:
			if selected_for_draft.has(card):
				selected_for_draft.remove_at(selected_for_draft.find(card))
				card.slide_to_position(card.position.x, card.position.y + 40, 0.0, 0.1)
			else:
				if selected_for_draft.size() < draft_limit:
					selected_for_draft.append(card)
					card.slide_to_position(card.position.x, card.position.y - 40, 0.0, 0.1)
		return
	selected_worker = card
	if fsm.state == fsm.FSMState.H_CLIENT:
		fsm.state_nodes[fsm.FSMState.H_CLIENT].assign_task_to_worker()


func select_slot(slot):
	if selected_worker == null:
		return
	if active_workers.has(selected_worker):
		active_workers[active_workers.find(selected_worker)] = null
	if hand.has(selected_worker):
		hand.remove_at(hand.find(selected_worker))
	active_workers[slot_buttons.find(slot)] = selected_worker
	selected_worker.slide_to_position(slot.position.x, slot.position.y, 0.0, 0.3)
	selected_worker = null


func _on_area_2d_input_event(_viewport, event, _shape_idx):
	if event is InputEventMouseButton and event.pressed:
		fsm.change_state(fsm.FSMState.WORKER)


func _on_area_2d_2_input_event(_viewport, event, _shape_idx):
	if event is InputEventMouseButton and event.pressed:
		fsm.change_state(fsm.FSMState.MANAGEMENT)


func _on_task_draw_deck_button_pushed(_button):
	fsm.change_state(fsm.FSMState.H_CLIENT)


func evaluate_task_success(num):
	var successfulness = 0
	var worker = active_workers[num]
	var client = active_clients[num]
	match client.services.size():
		2, 3:
			successfulness = 2
		4:
			successfulness = 1
			if worker.services.has(client.services[3]):
				successfulness = 2
		5:
			successfulness = 1
			if worker.services.has(client.services[4]):
				successfulness = 2
		6:
			successfulness = 0
			if worker.services.has(client.services[3]) or worker.services.has(client.services[4]):
				successfulness = 1
			if worker.services.has(client.services[5]):
				successfulness = 2
		7:
			successfulness = 0
			if worker.services.has(client.services[3]) or worker.services.has(client.services[4]):
				successfulness = 1
			if worker.services.has(client.services[5]) or worker.services.has(client.services[6]):
				successfulness = 2
	var slide_destination : Vector2
	match successfulness:
		0:
			poor_discard.append(client)
			slide_destination = $PoorDiscardPile.position
		1:
			good_discard.append(client)
			slide_destination = $GoodDiscardPile.position
		2:
			great_discard.append(client)
			slide_destination = $GreatDiscardPile.position
	client.slide_to_position(slide_destination.x, slide_destination.y, 0.0, 0.2)
	client.z_index = 0
	active_clients[num] = null


func worker_exceeded_capacity(num):
	active_workers[num].stress = 0
	active_workers[num].set_process(false)
	active_workers[num].visible = false
	workers.remove_at(workers.find(active_workers[num]))
	active_workers[num] = null


func draft_workers(_draw, pick):
	draft_limit = pick
	shown_for_draft = []
	selected_for_draft = []
	var y = 0
	var x = (250.0 * _draw) / 2.0
	shown_for_draft.append_array(board.draw_worker(_draw))
	for i in shown_for_draft.size():
		var card = shown_for_draft[i]
		card.visible = true
		card.set_process(true)
		card.card_clicked.connect(select_card)
		var ratio = float(i) / float(_draw - 1)
		var xx = lerpf(-1 * x, x, ratio)
		card.slide_to_position(xx, y, 0.0, 0.3)
	fsm.change_state(fsm.FSMState.DRAFT)


func pad_shift_deck():
	var padding = (2 + (2 * board.round_num)) - shift_deck.size()
	shift_deck.append_array(board.draw_client(padding))


func process_discard_decks():
	poor_discard.shuffle()
	good_discard.shuffle()
	great_discard.shuffle()
	for x in range(poor_discard.size() - 1, -1, -1):
		if x == 0:
			shift_deck.append(poor_discard[x])
		else:
			board.discard_client(poor_discard[x])
		poor_discard[x].position = Vector2(9999, 9999)
		poor_discard[x].visible = false
		poor_discard.remove_at(x)
	for x in range(good_discard.size() - 1, -1, -1):
		if x <= int(good_discard.size() / 2.0):
			shift_deck.append(good_discard[x])
		else:
			board.discard_client(good_discard[x])
		good_discard[x].position = Vector2(9999, 9999)
		good_discard[x].visible = false
		good_discard.remove_at(x)
	for x in range(great_discard.size() - 1, -1, -1):
		if x < great_discard.size() - 1:
			shift_deck.append(great_discard[x])
		else:
			board.discard_client(great_discard[x])
		great_discard[x].position = Vector2(9999, 9999)
		great_discard[x].visible = false
		great_discard.remove_at(x)

