extends Camera2D

@export var target_res : Vector2 = Vector2(480, 270)
@export var target_zoom : float = 1
@export var cam_speed : float = 5.0
@export var min_speed : float = 0.1
@export var ui_layer : CanvasLayer

@export_range(0.0, 1.0) var mouse_look_strength : float = 0.15 

@export var shake_decay : float = 5.0
@export var max_offset : Vector2 = Vector2(10, 10)

@onready var pixel_material : ShaderMaterial = $Pixelator.material

var scaling : Vector2
var actual_pos : Vector2

var shake_trauma : float = 0.0

func _ready():
	get_viewport().size_changed.connect(_on_viewport_resized)
	EventBus.player_dmg.connect(_on_player_dmg)
	EventBus.screenshake.connect(_on_screenshake)
	
	_on_viewport_resized()

func _fract(x : Vector2) -> Vector2:
	return x - floor(x)
	
func _on_player_dmg():
	add_shake(0.5)

func _on_screenshake(intensity: float):
	add_shake(intensity)

func add_shake(amount: float):
	shake_trauma = clamp(shake_trauma + amount, 0.0, 1.0)

func _apply_shake():
	var amount = pow(shake_trauma, 2)
	var offset := Vector2(
		max_offset.x * amount * randf_range(-1, 1),
		max_offset.y * amount * randf_range(-1, 1)
	)
	global_position = floor(actual_pos + offset)

func _on_viewport_resized():
	var viewport_res : Vector2 = get_viewport().get_visible_rect().size
	scaling = Vector2(viewport_res.x / target_res.x, viewport_res.y / target_res.y)
	
	if has_node("Pixelator"):
		var pixel_rect : ColorRect = get_node("Pixelator")
		pixel_rect.position = -target_res / 2.
		pixel_rect.size = target_res

	zoom = scaling * target_zoom
	if ui_layer:
		ui_layer.scale = zoom
	EventBus.debug_print.emit("new scaling: " + str(scaling))


func _process(delta : float):
	var parent_pos : Vector2 = get_parent().global_position

	var mouse_pos := get_viewport().get_mouse_position()
	var vp_size := get_viewport().get_visible_rect().size
	var center := vp_size / 2.0
	
	var offset_from_center := mouse_pos - center
	
	offset_from_center *= mouse_look_strength
	
	if scaling.x != 0 and scaling.y != 0:
		var world_offset := offset_from_center / scaling
		parent_pos += world_offset

	var dist := actual_pos.distance_to(parent_pos)
	var speed : float = max(min_speed, dist * cam_speed) * delta

	actual_pos = actual_pos.move_toward(parent_pos, speed)

	if shake_trauma > 0:
		shake_trauma = max(shake_trauma - shake_decay * delta, 0)
		_apply_shake()
	else:
		global_position = floor(actual_pos)

	var sub_pixels : Vector2 = floor(_fract(actual_pos) * scaling)

	if pixel_material:
		pixel_material.set_shader_parameter("cam_pos", sub_pixels)
		pixel_material.set_shader_parameter("scaling", scaling)
