extends Node2D
class_name Scene

const gs = preload("res://GameScript.gd")
#@onready var gamescript: gs = %GameScript
@onready var ScriptBuilder = $GameScript


@onready var map = NavigationServer2D.map_create()
@onready var region = NavigationServer2D.region_create()
@export var camera:Camera2D 
@onready var pathfind = $pathfind
var ego

signal transitioned(Scene)

@export var background_scale = 1.0


var start_scale_point : ScalePoint
var end_scale_point : ScalePoint
@export var starting_point: Vector2
func _ready():
	ScriptBuilder =get_node("/root/Node2D/GameScript")
	NavigationServer2D.region_set_navigation_polygon(region, $pathfind.navigation_polygon)
	NavigationServer2D.region_set_map(region, map)
	NavigationServer2D.map_set_active(map, true)
	var graham = load("res://Ego.tscn").instantiate()
	
	if starting_point:
		graham.position = starting_point
	else:
		if find_child("default-starting-point"):
			graham.position = find_child("default-starting-point").position
	
	add_child(graham)
	ego = graham
	#ego.find_node("AnimationPlayer").play("west")
	#ego.find_node("AnimationPlayer").stop()
	self.start_scale_point = $StartScalePoint
	self.end_scale_point = $EndScalePoint
	var tree = get_tree()
	camera = $"../Camera2D"
	
	

# Called every frame. 'delhideta' is the elapsed time since the previous frame.
func _process(delta):
	#print(ScriptBuilder.current_script)
	if ScriptBuilder and  ScriptBuilder.current_script:
		ScriptBuilder.current_script.step(delta, get_node("/root/Node2D"))

#func ego_scale(ego:Node2D):
	#
	#var value_sum = 0.0
	#var weight_sum = 0.0
	#
	#if $Graham and $Graham.position:
		#for c in get_children():
			#if c is ScalePoint:
				#var weight = 1.0 / $Graham.position.distance_to(c.position)
				#weight_sum += weight
				#var value = c.target_scale * weight
				#value_sum += value
		#return value_sum / weight_sum
	#else:
		#return 1.0
func ego_scale(ego:Node2D):
	if start_scale_point and end_scale_point:
		
		return remap(ego.position.y, start_scale_point.position.y, end_scale_point.position.y, start_scale_point.target_scale, end_scale_point.target_scale)
	return 1.0

#	var scale_points=[]
#	var total_distance = 0.0
#	for c in get_children():
#		if c is ScalePoint:
#			scale_points.append(c)
#			total_distance += ego.position.distance_to(c.position)
#
#	var inverse_distance_influence = []
#	for p in scale_points:
#		inverse_distance_influence.append ([ego.position.distance_to(p.position) / total_distance, p.target_scale])
#
#	inverse_distance_influence.sort()
#	var target_scale = 0.0
#	var remaining = 1.0
#	var should_print = rand_range(0.0, 20.0) <= 0.1
#	for p in inverse_distance_influence:
#		var weight = (1.0 - p[0]) * remaining 
#		remaining -= weight
#		target_scale += weight * p[1]
#		if should_print:
#			print("weight:", weight, " scale:", p[1])
#	if should_print:
#		print("")
##		inverse_distance_influence.append(z)
#
#
#	return target_scale
#
	
	
		
	#var start = ego.position.distance_to(start_scale_point.position)
	#var end = ego.position.distance_to(end_scale_point.position)
	
	#var magnitude = sqrt((start*start) + (end*end))
	#var start_influence = 1.0 - start/magnitude
	#var end_influence = 1.0 - end/magnitude
	#var start_influence = range_lerp(start * start, 0.0, smallest_influence * smallest_influence, 1.0, 0.0)
	#var end_influence = range_lerp(end * end, 0.0, smallest_influence * smallest_influence, 1.0, 0.0)
	#print ( "start:", start_influence, " end:", end_influence)


func _on_script_complete():
	ScriptBuilder.current_script = null 

func start_main_script(s):
	if ScriptBuilder.current_script and ScriptBuilder.current_script.interrupt():
		ScriptBuilder.current_script = s
	if not ScriptBuilder.current_script:
		ScriptBuilder.current_script = s

func _unhandled_input(event):
	if event is InputEventMouseButton and Input.is_action_just_released("interact"):
		# If a script is running and can't be interrupted, delegate to it
		if ScriptBuilder.current_script and not ScriptBuilder.current_script.can_interrupt:
			if ScriptBuilder.current_script.handle_input(event):
				return

		# Block input when inventory overlay is active
		var overlay = get_node_or_null("/root/Node2D/InventoryOverlay")
		if overlay and overlay is InventoryOverlay and overlay.is_active():
			return

		var root = get_node("/root/Node2D")
		# If look cursor is active and we got here, no SetPiece handled the input
		# so this is a room-wide look
		if ActionState.current_action == ActionState.Action.LOOK:
			_on_room_looked()
			return
		if ActionState.current_action == ActionState.Action.WALK:
			var path = NavigationServer2D.map_get_path(map, ego.position, pathfind.to_local(get_global_mouse_position()), true)
			start_main_script(ScriptBuilder.init(ScriptBuilder.walk_path(ego, path)).can_interrupt().build(self, "_on_script_complete"))
		if ActionState.current_action == ActionState.Action.ITEM:
			_on_item_use_in_world()

func _on_room_looked() -> void:
	# Default room look description - override in room scripts
	pass

func _on_item_use_in_world() -> void:
	if not InventoryManager.selected_item:
		return
	var item_id = InventoryManager.selected_item
	var top_piece = ActionState.get_top_hovered_setpiece()
	if top_piece:
		_use_item_on_setpiece(item_id, top_piece)
	else:
		_on_item_used_empty_space(item_id)

func _use_item_on_setpiece(item_id: String, piece: SetPiece) -> void:
	if piece.has_method("_on_item_used"):
		piece._on_item_used(item_id)
	else:
		var def = InventoryManager.get_item_definition(item_id)
		var item_name = item_id
		if def:
			item_name = def.name
		var piece_name = piece.label if piece.label else piece.name
		start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "I can't use the %s on the %s." % [item_name, piece_name])).build(self, "_on_script_complete"))

func _on_item_used_empty_space(item_id: String) -> void:
	var def = InventoryManager.get_item_definition(item_id)
	var item_name = item_id
	if def:
		item_name = def.name
	start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "There's nothing to use the %s on here." % [item_name])).build(self, "_on_script_complete"))

func give_item(item_id: String) -> void:
	InventoryManager.acquire_item(item_id)

func remove_item(item_id: String, quiet: bool = false) -> void:
	InventoryManager.remove_item(item_id, quiet)

func strip_items(event_items: Array[String], exempt_items: Array[String] = []) -> void:
	InventoryManager.bulk_strip_items(event_items, exempt_items)
