extends Camera2D

var horizontal_facing = 0
var vertical_facing = 0
var camera_vertical_shift = 0
var move_time: float = 0
var slow_time: float = 0
var original_limit_left: int
var original_limit_right: int
var original_limit_bottom: int
var original_limit_top: int
var camera_is_panning: bool = false
var target_offset: Vector2 = Vector2(0,0)

export var camera_horizontal_shift = 80
export var offset_reset_seconds := 1
export var offset_adapt_seconds := 0.8

onready var shiftLeft = $CameraAnimationPlayer.get_animation("shiftingLeft")
onready var shiftRight = $CameraAnimationPlayer.get_animation("shiftingRight")
onready var shiftCenter = $CameraAnimationPlayer.get_animation("shiftingCenter")
onready var anim_player = $CameraAnimationPlayer
onready var original_x_zoom = zoom.x
onready var original_y_zoom = zoom.y
onready var blobby = get_node("%Blobby")
onready var screen_rect = Vector2(ProjectSettings.get_setting("display/window/size/width") * zoom.x, ProjectSettings.get_setting("display/window/size/height") * zoom.y )

var image = Image.new()
var texture = ImageTexture.new()

# Gets the camera limits from the tilemap of the level
# Requires "TileMap" to be a sibling of blobby
func _ready():
	_set_boundaries()
	print(screen_rect)
	self.position = blobby.global_position
	image.create(128, 2, false, Image.FORMAT_RGBAH)
	_update_lighting_shader()
	# TODO Trigger when needed
	get_node("LightAnimationPlayer").play("Pulsing")

func _physics_process(delta: float) -> void:
	if(!GlobalState.is_dead):
		var player_vel = blobby.velocity
		if(abs(player_vel.x) >= blobby.max_velocity["walk"]):
			move_time += delta
			slow_time = 0
		else:
			slow_time += delta
			move_time = 0
		
		_adapt_to_movement(player_vel)
	#TODO Do this via a event or let it be to track blobbies movement better
	else:
		self.position = blobby.global_position
		_death_cam()
	_update_lighting_shader()

func _set_boundaries():
	# This is ok, because it only happens on initialization
	# But it is also quite fickle
	var tilemap = get_node("../TileMap")
	# TODO: This goes wrong when overwriting old tiles with new sprites
	# New pngs -> completely new tiles and rebuild map
	var rect = tilemap.get_used_rect()
	var cell_size = tilemap.cell_size
	limit_right = rect.end.x * cell_size.x
	limit_left = rect.position.x * cell_size.x
	limit_top = rect.position.y * cell_size.y 
	limit_bottom = rect.end.y * cell_size.y 
	original_limit_left = limit_left
	original_limit_right = limit_right
	original_limit_top = limit_top
	original_limit_bottom = limit_bottom
	var screen_size = get_viewport_rect()
	var h_pixels = limit_right - limit_left
	var v_pixels = limit_bottom - limit_top
	# TODO: Fix that it can zoom both?
	if screen_size.end.x * original_x_zoom - h_pixels > 0:
		zoom.x = h_pixels / screen_size.end.x
		zoom.y = zoom.x
	if screen_size.end.y * original_y_zoom - v_pixels > 0:
		zoom.y = v_pixels / screen_size.end.y
		zoom.x = zoom.y

# Smoothing the camera limits in godot ruins something
func _adapt_to_movement(velocity: Vector2) -> void:
	var offset_track
	var center = get_camera_screen_center()
	var left_edge_pos = center.x - screen_rect.x/2 + camera_horizontal_shift
	var right_edge_pos = center.x + screen_rect.x/2 - camera_horizontal_shift
	if(move_time >= offset_adapt_seconds && !anim_player.is_playing()):
		target_offset.x = camera_horizontal_shift * sign(velocity.x)
		if(sign(velocity.x) < 0):
			offset_track = shiftLeft.find_track(".:offset")
			shiftLeft.track_set_key_value(offset_track, 0, offset)
			shiftLeft.track_set_key_value(offset_track, 1, target_offset)
			# limit_left = original_limit_left + camera_horizontal_shift
			var limit_left_track = shiftLeft.find_track(".:limit_left")
			var new_limit_left = original_limit_left + camera_horizontal_shift
			shiftLeft.track_set_key_value(limit_left_track, 0, limit_left)
			shiftLeft.track_set_key_value(limit_left_track, 1, new_limit_left)
			print("shiftleft")
			anim_player.play("shiftingLeft")
		else:
			offset_track = shiftRight.find_track(".:offset")
			shiftRight.track_set_key_value(offset_track, 0, offset)
			shiftRight.track_set_key_value(offset_track, 1, target_offset)
			# limit_right = original_limit_right - camera_horizontal_shift
			var limit_right_track = shiftRight.find_track(".:limit_right")
			var new_limit_right = original_limit_right - camera_horizontal_shift
			shiftRight.track_set_key_value(limit_right_track, 0, limit_right)
			shiftRight.track_set_key_value(limit_right_track, 1, new_limit_right)
			print("shiftright")
			anim_player.play("shiftingRight")
	elif(slow_time >= offset_reset_seconds && !anim_player.is_playing()):
		if(left_edge_pos > limit_left && limit_right > right_edge_pos):
			target_offset.x = 0
			offset_track = shiftCenter.find_track(".:offset")
			shiftCenter.track_set_key_value(offset_track, 0, offset)
			shiftCenter.track_set_key_value(offset_track, 1, target_offset)
			var limit_left_track = shiftCenter.find_track(".:limit_left")
			var limit_right_track = shiftCenter.find_track(".:limit_right")
			var limit_top_track = shiftCenter.find_track(".:limit_top")
			var limit_bottom_track = shiftCenter.find_track(".:limit_bottom")
			shiftCenter.track_set_key_value(limit_left_track, 0, limit_left)
			shiftCenter.track_set_key_value(limit_right_track, 0, limit_right)
			shiftCenter.track_set_key_value(limit_top_track, 0, limit_top)
			shiftCenter.track_set_key_value(limit_bottom_track, 0, limit_bottom)
			shiftCenter.track_set_key_value(limit_left_track, 1, original_limit_left)
			shiftCenter.track_set_key_value(limit_right_track, 1,original_limit_right)
			shiftCenter.track_set_key_value(limit_top_track, 1, original_limit_top)
			shiftCenter.track_set_key_value(limit_bottom_track, 1, original_limit_bottom)
			print("shiftcenter")
			anim_player.play("shiftingCenter")
			# reset_limits()
	position = blobby.position

func reset_limits() -> void:
	limit_left = original_limit_left
	limit_right = original_limit_right
	limit_bottom = original_limit_bottom
	limit_top = original_limit_top

func _death_cam():
	$CameraAnimationPlayer.play("deathCam")

func _update_lighting_shader():
	# Props to gameendaevour
	# TODO get this into a central world update management system
	var lights = get_tree().get_nodes_in_group("light")
	image.lock()
	for i in lights.size():
		var light = lights[i]
		# TODO To make the lighting affect all layers properly
		# I would have the access the global positions of nodes in different Z layers
		# without the projection to the global center layer.

		# var vtrans = get_canvas_transform()
		# var top_left = -vtrans.origin / vtrans.get_scale()
		# var vsize = get_viewport_rect().size
		# var t = Transform2D(0, (top_left + 0.5*vsize/vtrans.get_scale()).rotated(rotation))

		image.set_pixel(i, 0, Color(
			light.position.x, light.position.y,
			light.strength, light.radius
		))
		image.set_pixel(i, 1, light.color)
	image.unlock()

	texture.create_from_image(image)

	material.set_shader_param("n_lights", lights.size())
	material.set_shader_param("light_data", texture)
	material.set_shader_param("global_transform", get_global_transform())
	material.set_shader_param("viewport_transform", get_viewport_transform())
