extends Node2D

@onready var camera: Camera2D = $Camera2D
@onready var countdown: Timer = $countdown
#@onready var countdown_label: Label = $hud/countdown_label

@onready var cars: Node = $cars

@onready var game_hud_animations: AnimationPlayer = $hud/game_hud_animations

@onready var times_container: HFlowContainer = $hud/times_container
@onready var timer_close: Timer = $timer_close


const caroffset= 32+4 #space cars on start line

var viewCarMargin=Vector2(0.7,0.7) #1=zoom out full speed when car is at border. 0.9 zoom out full speed when car is 10% away from border
var viewCarMargin_zoomstart=viewCarMargin-Vector2(0.2,0.2) #start zooming 
var viewCarMargin_zoombackup=viewCarMargin_zoomstart-Vector2(0.1,0.1) #start zooming back in
var zoomspeed=0.5
var zoomspeed_backup=0.1 #relative to screen size
var zoom_normal=1.5
const CAMERA_POSITION_SPEED=0.02 #0.0 - 1.0, higher=faster
var camera_zoom_out_lookahead_time=1 #predicted position of car in t seconds for camera coverage. greater value=earlier zoom out and movement of camera

var running=false


var time_close_keypressed=1 #seconds to wait after key pressed at endscreen

var game_ended=false


# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	Gamestate.resetTimeElapsed()
	
	#countdown.start()
	game_hud_animations.play("game_start")
	#countdown_label.visible=true
	
	#Load Map
	var checkpoints :Array[String]=[]
	var mapscene=load(Gamestate.getSelectedMapSceneName())
	var mapsceneinstance=mapscene.instantiate()
	add_child(mapsceneinstance)
	for mapc in mapsceneinstance.get_children():
		if mapc.name.begins_with("area_cp"):
			checkpoints.append(mapc.name)
	
	print(str(checkpoints.size())+" Checkpoints found")
	
	var i=0
	for player in Gamestate.getPlayers(): #create all players
		var newcarscene=load("res://scenes/car.tscn")
		var newcarinstance=newcarscene.instantiate()
		cars.add_child(newcarinstance)
		newcarinstance.setPlayerinformation(i,player.color)
		
		newcarinstance.setPosition(Vector2(0,ceil(i/2.0)*(fmod(i,2)-0.5)*2.0*caroffset))
		newcarinstance.setCheckpoints(checkpoints,Gamestate.getRounds())
		newcarinstance.getCharacterBody().car_finished.connect(_on_car_finished)
		
		print("carpos is ="+str(newcarinstance.getPosition())+"  instancepos="+str(newcarinstance.position))
		i+=1
		

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if running:
		Gamestate.addTimeElapsed(delta)
	#if !countdown.is_stopped():
	#	countdown_label.text=str(round(countdown.time_left))
		
	updateCameraMovement(delta)
	
	#$hud/debuglabel.text=""+str(calculatedViewCarMargin)+" / "+str(viewCarMargin_zoomstart)+" zoomspeed="+str(mapped_zoomspeed)
	#$hud/debuglabel.text=""+str(calculatedViewCarMargin)+" / "+str(viewsize)+" zoomspeed="+str(mapped_zoomspeed)
	$hud/timer.text=str(round(Gamestate.getTimeElapsed()*1000)/1000.0)
	
	
	
	if game_ended:
		var anyplayerkeypressed=false
		var id=0
		for p in Gamestate.getPlayers():
			if Input.is_action_pressed(Gamestate.userinput_prefix+str(id)):
				anyplayerkeypressed=true
			id+=1
		if anyplayerkeypressed and timer_close.time_left<time_close_keypressed:
			timer_close.wait_time=time_close_keypressed #set time back
			timer_close.stop() #prepare for restarting at this time
		if !anyplayerkeypressed and timer_close.is_stopped():
			timer_close.start() #start timer when no key is pressed

func updateCameraMovement(delta: float):
	
	var cars=cars.get_children()
	var displayedCarCount=0
	var maxCarSpeed=0
	var minPos=Vector2.ZERO #min/max x and y position of all cars
	var maxPos=Vector2.ZERO
	
	var oneDriving=false
	for c in cars: #check if any one car is still driving
		if !c.hasFinished():
			oneDriving=true
			
	for c in cars:
		if !c.hasFinished() or !oneDriving:
			var carpos = c.getPosition()
			var carposLookahead= c.getPositionLookahead(camera_zoom_out_lookahead_time)
			$hud/debuglabel.text=""+str(carpos)+"\n"+str(carposLookahead)
			
			maxCarSpeed=max(maxCarSpeed,c.getSpeed())
			if displayedCarCount==0:
				minPos=carpos.min(carposLookahead)
				maxPos=carpos.max(carposLookahead)
			else:
				minPos=minPos.min(carpos).min(carposLookahead)
				maxPos=maxPos.max(carpos).max(carposLookahead)
			
			displayedCarCount+=1
		
	
	camera.position=lerp(camera.position,(minPos+maxPos)/2.0,CAMERA_POSITION_SPEED)

	
	
	var viewsize = camera.get_viewport_rect().size
	var carSpread=Vector2(maxPos.x-minPos.x,maxPos.y-minPos.y)
	var calculatedViewCarMargin=carSpread*camera.zoom #when cars are screen width apart this number matches  viewsize=camera.get_viewport_rect().size
	
	
	var viewCarMargin_zoomstart_pixels=viewCarMargin_zoomstart*viewsize/camera.zoom
	var viewCarMargin_pixels=viewCarMargin*viewsize/camera.zoom
	var viewCarMargin_zoombackup_pixels=viewCarMargin_zoombackup*viewsize/camera.zoom
	
	var mapped_zoomspeed_x=constrain(remap(calculatedViewCarMargin.x , viewCarMargin_zoomstart_pixels.x,viewCarMargin_pixels.x,0,zoomspeed),0,zoomspeed)
	var mapped_zoomspeed_y=constrain(remap(calculatedViewCarMargin.y , viewCarMargin_zoomstart_pixels.y,viewCarMargin_pixels.y,0,zoomspeed),0,zoomspeed)
	var mapped_zoomspeed=max(mapped_zoomspeed_x,mapped_zoomspeed_y)
	if calculatedViewCarMargin.x>viewCarMargin_zoomstart_pixels.x or calculatedViewCarMargin.y>viewCarMargin_zoomstart_pixels.y: #cars not in view
		camera.zoom-=Vector2(mapped_zoomspeed*delta,mapped_zoomspeed*delta)
	elif calculatedViewCarMargin.x<viewCarMargin_zoombackup_pixels.x and calculatedViewCarMargin.y<viewCarMargin_zoombackup_pixels.y: #cars in view again
		
		if camera.zoom.x<zoom_normal:
			camera.zoom+=Vector2(zoomspeed_backup*delta,zoomspeed_backup*delta)

func _input(ev):
	#if ev is InputEventKey and 
	if Input.is_action_just_pressed("ui_cancel"):
		get_tree().change_scene_to_file("res://scenes/menu.tscn")
		
		
func checkPositionInsideView(checkpos: Vector2) -> bool:
	
	var viewsize = camera.get_viewport_rect().size
	var canvas_pos = camera.get_viewport().get_canvas_transform().affine_inverse() * -checkpos
	
	print("cp="+str(canvas_pos) + "  viewsize="+str(viewsize))

	if canvas_pos.x < 0 and canvas_pos.x > -viewsize.x:
		if canvas_pos.y < 0 and canvas_pos.y > -viewsize.y:
			return true
	return false
			

func constrain(val,a,b):
	var vmin=min(a,b)
	var vmax=max(a,b)
	return min(vmax,max(vmin,val))
	
func constrain2(val:Vector2,a:Vector2,b:Vector2):
	var vmin=a.min(b)
	var vmax=a.max(b)
	return vmax.min(vmin.max(val))


func _on_countdown_timeout() -> void:
	running=true
	var cars=cars.get_children()
	for c in cars:
		c.setRunning(true)
	#countdown_label.visible=false
	
	
func _on_car_finished(playerid,finalTime) -> void:
	times_container.addFinishedPlayer(playerid,finalTime)
	
	if times_container.getPlayersFinished() == Gamestate.getPlayers().size(): #all players have finish times
		finishGame()# Game finished
		
		

func finishGame():
	print("Game Finished")
	running=false
	game_ended=true
	game_hud_animations.play("game_end")
	timer_close.start()
	#overlaycolor.visible=true
	


func _on_timer_close_timeout() -> void:
	print("Close Map")
	get_tree().change_scene_to_file("res://scenes/menu.tscn")
	
	
