extends KinematicBody

signal starved_to_death

const StateDefault = preload("res://scripts/player/state/default.gd")
const StateInteracting = preload("res://scripts/player/state/interacting.gd")
const StateSleeping = preload("res://scripts/player/state/sleeping.gd")

const SPEED = 10.0
const MAX_HEALTH = 4

export var hunger_tick_time = 30.0
export var inventory = {}

var health: int = 4 setget set_health
var item_in_hand
var move_enabled: bool = true

onready var anim_tree = $model_transform/DungMan/AnimationTree
onready var move_playback = anim_tree["parameters/Move/playback"]
onready var hunger_timer = $"%hunger_timer"

var state = null

func _ready():
	$hitbox.set_meta("owner", self)
	move_playback.travel("idle")
	hunger_timer.wait_time = hunger_tick_time
	hunger_timer.start()
	state = StateDefault.new()
	state.ctx = self
	state.enter_from(null)
	print("player: NULL -> ", state.NAME)

func change_state(new_state):
	print("player: ", state.NAME, " -> ", new_state.NAME)
	new_state.ctx = self
	state.exit_to(new_state)
	new_state.enter_from(state)
	state = new_state

func _physics_process(delta):
	state.physics_process(delta)

func _on_hunger_timer_timeout():
	set_health(health - 1)
	print("player: lost health to hunger tick")

func set_health(new_value):
	health = min(new_value, MAX_HEALTH)
	for child in $"%stomachs".get_children():
		child.visible = child.get_index() < health
	if health <= 0:
		emit_signal("starved_to_death")

func consume_food(item : Resource):
	set_health(MAX_HEALTH)
	print("player: Hunger Satisfied! Ate %s" % item.name)

func can_afford(item_name, item_amount):
	assert(item_amount > 0)
	var current_amount : int = 0
	if(inventory.has(item_name)):
		current_amount = inventory[item_name]
	return current_amount >= item_amount
	
func modify_inventory(item_name, item_amount):
	if item_amount == 0:
		return true
		
	var is_op_valid : bool = true
	
	# Note(asr): check if you can afford the item if we are removing
	# for item grants op is always valid
	if item_amount < 0:
		is_op_valid = can_afford(item_name, abs(item_amount))
		
	if not is_op_valid:
		return false
	
	var current_amount : int = 0
	if inventory.has(item_name):
		current_amount = inventory[item_name]
	# Note(asr): clamp to 0. can't have negative items
	var new_amount : int = max(current_amount + item_amount, 0)
	inventory[item_name] = new_amount
	print("inventory updated: ", item_name, " : ", new_amount)
	return true

func _unhandled_input(event):
	state.unhandled_input(event)

func drop_item_in_hand():
	print("player dropped ", item_in_hand.item_name)
	var item_dropped = item_in_hand
	$"%ItemSpawn".remove_child(item_in_hand)
	item_in_hand = null
	return item_dropped
	
func pick_up_item(item):
	var item_dropped = null
	if item_in_hand != null:
		item_dropped = drop_item_in_hand()
	item_in_hand = item
	$"%ItemSpawn".add_child(item_in_hand)
	print("player picked up ", item_in_hand.item_name)
	return item_dropped

func has_item() -> bool:
	return item_in_hand != null

func get_item_in_hand():
	var item_to_return = null
	if item_in_hand != null:
		item_to_return = drop_item_in_hand()
	return item_to_return

func _on_blink_timer_timeout():
	anim_tree["parameters/Blink/active"] = true
	$"%blink_timer".wait_time = rand_range(0.5, 3.0)

func sleep(made_it_to_bed: bool, hop_position: Spatial):
	state.on_sleep(made_it_to_bed, hop_position)

