extends Control


const letter_count := 5
const guess_count := 6

const Letter = preload("res://src/Letter.tscn")

export var color_incorrect: Color = Color()
export var color_misplaced: Color = Color()
export var color_correct: Color = Color()

# An array of arrays of the letter nodes
var letters := []

var target_word: String
var current_guess: int
var ended: bool
var input_guess: String

onready var error_text_color_default = $C/V/V/ErrorText.get("custom_colors/font_color")


func _ready() -> void:
	for _i in range(guess_count):
		var letter_array := []
		for _j in range(letter_count):
			var letter := Letter.instance()
			letter_array.append(letter)
			$C/V/LetterGrid.add_child(letter)
		letters.append(letter_array)

	var random_seed = null
	if Global.daily_mode:
		var current_time := OS.get_datetime_from_unix_time(OS.get_unix_time())
		current_time["hour"] = 0
		current_time["minute"] = 0
		current_time["second"] = 0
		random_seed = OS.get_unix_time_from_datetime(current_time)

		$C/V/Title.text = "Daily " + $C/V/Title.text
	else:
		$C/V/Title.text = "Random " + $C/V/Title.text

	target_word = Global.generate_word(letter_count, random_seed)
	current_guess = 0
	ended = false


func type_letter(letter: String) -> void:
	if ended or input_guess.length() >= 5:
		return
	var index := input_guess.length()
	letter = letter[0]
	input_guess += letter
	var letter_instance := letters[current_guess][index] as ColorRect
	letter_instance.get_node("Label").text = letter


func backspace() -> void:
	if ended or input_guess.length() <= 0:
		return
	input_guess = input_guess.substr(0, input_guess.length() - 1)
	var index := input_guess.length()
	var letter_instance := letters[current_guess][index] as ColorRect
	letter_instance.get_node("Label").text = ""


func _unhandled_key_input(event: InputEventKey) -> void:
	if event.is_pressed():
		var scancode = event.get_scancode()
		if scancode >= KEY_A and scancode <= KEY_Z:
			var letter := OS.get_scancode_string(scancode)
			type_letter(letter)
			get_tree().set_input_as_handled()
		elif scancode == KEY_BACKSPACE:
			backspace()
			get_tree().set_input_as_handled()
		elif scancode == KEY_ENTER:
			guess_entered()
			get_tree().set_input_as_handled()


func _on_GuessButton_pressed() -> void:
	guess_entered()


func guess_entered() -> void:
	if current_guess >= guess_count:
		return
	input_guess = input_guess.to_upper()
	if input_guess.length() != letter_count:
		show_error("Word must be five characters.")
		return
	if not Global.is_valid_word(input_guess):
		show_error("Not a recognized word.")
		return

	var letters_remaining = []
	for letter in target_word:
		letters_remaining.append(letter)

	hide_error()

	# Mark all greens
	for i in range(letter_count):
		var guess_letter := input_guess[i]
		var target_letter := target_word[i]

		var letter_instance := letters[current_guess][i] as ColorRect
		letter_instance.get_node("Label").text = guess_letter
		if guess_letter == target_letter:
			letter_instance.color = color_correct
			# Remove that one letter from remaining letters (is there a function for this?)
			for j in range(letters_remaining.size()):
				if letters_remaining[j] == guess_letter:
					letters_remaining.remove(j)
					break

	# Mark all yellows (and grays)
	for i in range(letter_count):
		var letter_instance := letters[current_guess][i] as ColorRect
		if letter_instance.color == color_correct:
			# Ignore things that are already green
			continue
		var guess_letter := input_guess[i]
		var found := false
		for j in range(letters_remaining.size()):
			if letters_remaining[j] == guess_letter:
				found = true
				letters_remaining.remove(j)
				break
		if found:
			letter_instance.color = color_misplaced
		else:
			letter_instance.color = color_incorrect

	current_guess += 1

	var won := false

	if input_guess == target_word:
		ended = true
		won = true
	elif current_guess >= guess_count:
		ended = true

	input_guess = ""

	if ended:
		find_node("GuessButton").disabled = true
		if won:
			show_error("Congrats! You won!", Color(0.4, 0.9, 0.6))
		else:
			show_error("Game Over. The word was %s" % target_word, error_text_color_default)


func show_error(text: String, color = null):
	$C/V/V/ErrorText.text = text
	if typeof(color) == TYPE_COLOR:
		$ErrorFadeOut.stop()
		$C/V/V/ErrorText.add_color_override("font_color", color)
	else:
		$ErrorFadeOut.play("ErrorFadeOut")


func hide_error():
	$C/V/V/ErrorText.text = ""
	$ErrorFadeOut.stop()


func _on_MenuButton_pressed() -> void:
	# TODO check if game is in progress and show confirmation popup
	var error := get_tree().change_scene("res://src/Menu.tscn")
	assert(not error)