extends Node

#Dedicated to the brilliant women in my life.

var valid_words = {}
var playerEntry = []
#var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
var alphabet = []
var lScores = {	"E": 1, "S": 1, "I": 1, "A" : 1, "R" : 1, "N": 1, "T": 1, "O": 1, "L": 1,
				"C": 2, "D": 2, "U": 2, "P": 2, "M": 2, "G": 2, "H": 2, "B": 2,
				"Y": 3, "F": 3, "V": 3,
				"K": 4, "W": 4,
				"Z": 5,
				"X": 6,
				"J": 8, "Q": 8}
var lCount = {	"E": 0, "S": 0, "I": 0, "A": 0, "R": 0, "N": 0, "T": 0, "O": 0, "L": 0,
				"C": 0, "D": 0, "U": 0, "P": 0, "M": 0, "G": 0, "H": 0, "B": 0,
				"Y": 0, "F": 0, "V": 0,
				"K": 0, "W": 0,
				"Z": 0,
				"X": 0,
				"J": 0, "Q": 0,
				" ": 0}

var rows = 8
var columns = 6

@onready var background = get_node("/root/Screen/CanvasLayer/Background")
@onready var submitButton = get_node("/root/Screen/CanvasLayer/SubmitButton")
@onready var scoreDisplay = get_node("/root/Screen/CanvasLayer/ScoreBox")
@onready var scoreLog = get_node("/root/Screen/CanvasLayer/WordLog")
@onready var rawCells = get_tree().get_nodes_in_group("gridCell")
@onready var freeInserters = get_tree().get_nodes_in_group("letterInserter")
@onready var gameOverUI = get_node("/root/Screen/CanvasLayer/GameOver")
@onready var highScoreBox = get_node("/root/Screen/CanvasLayer/GameOver/HighScoreBox")
var busyInserters = []
var cells = []

var gameOverMode = false
var playerString :String = ""
var score = 0
var totalWords = 0
var currentActiveCells = 0
var mainInsertionCooldown :float = 3.0
var letterMaxCooldown = 15.0
var perLetterWindup = 4

var highscorePath = "res://high_scores.txt"
var dictionaryPath = "res://dictionary.txt"

func _ready() -> void:
	gameOverUI.visible = false
	get_tree().quit_on_go_back = true
	#Find all your cells and initialize them
	cells = create_2d_array(rows,columns,null)
	for cell in rawCells:
		cells[cell.row][cell.column]=cell
	#Each cell now has a position in the cells array and an initial letter value
	#initialize the dictionary
	var f := FileAccess.open(dictionaryPath, FileAccess.READ)
	if f:
		while not f.eof_reached():
			var word := f.get_line().strip_edges().to_upper()
			if word != "":
				valid_words[word] = true
		f.close()
	if valid_words.size() == 0:
		#Debug in case the dang dictionary doesn't export again.
		background.color = Color.RED

func _process(delta: float) -> void:
	currentActiveCells = 0
	
	for column in range(columns):
		for row in range(rows):
			var cell = cells[row][column]
			if cell.startFilled:
				cell.startFilled = false
				cell.text = randomLetter()
				cell.disabled = false
			if cell.clearNextFrame:
				cell.clearNextFrame = false
				cell.button_pressed = false
				if cell.scored:
					cell.emptyNextFrame = true
				cell.scored = false
				#At this point we know the board is clear of all score related changes
				#Now we can do the drop, as well as inserting any new characters from the top
			if cell.emptyNextFrame:
				#change this to an empty cell.
				cell.emptyNextFrame = false
				cell.text = " "
				cell.disabled = true
			if !cell.disabled:
				currentActiveCells += 1
				var destination = null
				var i = 1
				while (row - i) >= 0:
					if cells[row - i][column].disabled:
						destination = cells[row - i][column]
					else:
						break
					i += 1
				if destination != null:
					destination.disabled = false
					destination.text = cell.text
					cell.text = " "
					cell.disabled = true
				#look at each cell below this until you find a full one or the bottom.
				#Then, if you found any empty cells, put this value in that cell.
				#otherwise, you're done.
				pass
	updatePlayerEntry()
	
	#Inserting more letters:
	mainInsertionCooldown -= delta
	#$"../CanvasLayer/globalLetterCooldown".text = str(mainInsertionCooldown)
	var lettersOnBoard = columns - freeInserters.size() + currentActiveCells
	var timeScalarFromEmptyness  = clampf(float(currentActiveCells) / ((1+rows) * columns), 0, 1)
	var timePenaltyFromWords = totalWords * 0.25
	if ((mainInsertionCooldown <= 0 || lettersOnBoard <6) && freeInserters.size() > 0):
		mainInsertionCooldown = clampf(letterMaxCooldown * timeScalarFromEmptyness - timePenaltyFromWords, 1, 30)
		var selectedInserter = freeInserters[randi_range(0,freeInserters.size()-1)]
		busyInserters.append(selectedInserter)
		freeInserters.erase(selectedInserter)
		selectedInserter.letter = randomLetter()
		var initialTimerValue = clampf((perLetterWindup - 0.1 * totalWords) * timeScalarFromEmptyness, 0.25, 5)
		selectedInserter.max_value = initialTimerValue
		selectedInserter.RemainingTime = initialTimerValue
		

func insertLetter(targetCol, letter):
	#var inputCell = cells[rows-1][randi_range(0,columns-1)]
	var inputCell = cells[rows-1][targetCol]
	if inputCell.disabled == true:
		inputCell.disabled = false
		inputCell.text = letter
	else:
		if !gameOverMode:
			GameOver()

func GameOver():
	gameOverUI.visible = true
	gameOverMode = true
	var highscorefile = FileAccess.open(highscorePath, FileAccess.READ_WRITE)
	var previousHighScore = int(highscorefile.get_line())
	if score > previousHighScore:
		highscorefile.seek(0)
		highscorefile.store_line(str(score))
		highscorefile.flush()
		highscorefile.close()
		highScoreBox.text = "New High Score! \n Previous Best: " + str(previousHighScore) + "\n" + "Your score: " + str(score)
	else:
		highscorefile.close()
		highScoreBox.text = "High Score: " + str(previousHighScore) + "\n" + "Your score: " + str(score)

func updatePlayerEntry():
	playerString = ""
	for cell in playerEntry:
		playerString += cell.text
	if playerString.length() == 0:
		playerString = "..."
	submitButton.text = playerString

func press(cell):
	playerEntry.append(cell)

func randomLetter() -> String:
	alphabet.clear()
	updateLetterCount()
	for entry in lScores:
		var balancedCount = clampi(8/(lScores[entry]+1)-lCount[entry],0,10)
		for i in (balancedCount):
			alphabet.append(entry)
	return alphabet[randi_range(0,alphabet.size()-1)]

func updateLetterCount():
	for entry in lCount:
		#reset all to 0
		lCount[entry] = 0
	for column in range(columns):
		for row in range(rows):
			#print(str(row)+" "+str(column)+" "+str(cells[row][column]))
			var cell = cells[row][column]
			if cell.text:
				lCount[cell.text] += 1

func isAWord(entry: String) -> bool:
	entry = entry.strip_edges().to_upper()

	if entry == "DISCO":
		background.discoMode = !background.discoMode

	if valid_words.has(entry):
		return true
	return false
	
func create_2d_array(height, width, value):
	var a = []
	for y in range(height):
		a.append([])
		a[y].resize(width)
		for x in range(width):
			a[y][x] = value
	return a

func submit():
	#Test to see if a word is good, if so, score the points and clear the cells.
	var scoring = isAWord(playerString)
	if scoring && !gameOverMode:
		var award = scoreWord(playerString)
		score += award
		scoreDisplay.text = str(score)
		scoreLog.text += "\n" + playerString + ": " + str(award)
		#print(playerString + " is a word worth " + str(award) + " points!")
	
	for cell in playerEntry:
		cell.clearNextFrame = true
		if scoring:
			cell.scored = true

func scoreWord(word: String):
	var totalScore = 0
	for c in word:
		for entry in lScores:
			if c == entry:
				totalScore += lScores[entry]
	totalWords += 1
	return totalScore * word.length()

func NewGame():
	get_tree().reload_current_scene()

func _on_submit_button_pressed() -> void:
	submit()

func _on_new_game_button_pressed() -> void:
	NewGame()
