class_name GameManagerType extends Node
## Autoloaded singleton encapsulating game state.

## Emitted just after `delta` is added to the player's grunk tank.
signal grunk_collected(delta: float)

## Emitted just after the grunk tank is emptied, where `amount` is how much had been collected.
signal grunk_emptied(amount: float)

## Emitted just before the alert level is raised to `new_value`.
signal alert_raised(new_value: int)

## Emitted just before the alert level is reset to zero.
signal alert_cleared

## Emitted after the player's grunk vault reaches a new milestone.
signal milestone_reached(milestone: Milestone)

const MAX_ALERT := 6

## Maximum amount of grunk the player can carry in their tank.
@export var grunk_tank_limit := 120000

# TODO figure this out
@export var grunk_quota := 2000000

## Grunk collection milestones
@export var vault_milestones: Dictionary[int, Milestone]

## Amount of grunk the player is currently carrying.
var grunk_tank := 0.0

## Total amount of grunk that has been deposited by the player.
var grunk_vault := 0.0

## Level of grunk agressiveness, raised whenever the player messes up.
var alert_level := 0


## Add to the player's grunk tank.
func collect_grunk(delta: float) -> void:
	grunk_tank += delta
	grunk_collected.emit(delta)


## Empty the player's grunk tank, e.g. when depositing grunk.
func empty_tank() -> void:
	var amount := grunk_tank
	grunk_tank = 0.0
	grunk_emptied.emit(amount)


## Deposit the player's grunk in the vault, emptying the player's tank.
func deposit_tank() -> void:
	var prev_milestone := latest_milestone()
	grunk_vault += grunk_tank
	empty_tank()
	var new_milestone := latest_milestone()
	if new_milestone != prev_milestone:
		milestone_reached.emit(new_milestone)


func is_tank_full() -> bool:
	return grunk_tank >= grunk_tank_limit


func get_tank_fill_pct() -> float:
	return grunk_tank / grunk_tank_limit


## Raise the alert level, if possible.
func raise_alert(delta: int) -> void:
	var new_value := clampi(alert_level + delta, 0, MAX_ALERT)
	if new_value != alert_level:
		alert_raised.emit(new_value)
	alert_level = new_value


## Reset the alert level to zero.
func clear_alert() -> void:
	alert_cleared.emit()
	alert_level = 0


## Returns the latest vault milestone reached by the player.
##
## Returns null if the player has not reached a milestone (shouldn't be possible).
func latest_milestone() -> Milestone:
	var prev: Milestone = null
	for milestone_amt: int in vault_milestones:
		if grunk_vault < milestone_amt:
			return prev
		prev = vault_milestones[milestone_amt]
	return prev


## Returns the next vault milestone for the player to reach.
##
## Returns null if all milestones have been reached.
func next_milestone() -> Milestone:
	var amt := next_milestone_amount()
	if amt >= 0:
		return vault_milestones[amt]
	return null


## Returns the grunk amount needed for the player to reach the next milestone.
##
## Returns <0 if all milestones have been reached.
func next_milestone_amount() -> int:
	for milestone_amt: int in vault_milestones:
		if grunk_vault < milestone_amt:
			return milestone_amt
	return -1
