extends CharacterBody3D

const camera_SPEED = 3.5
const Run_SPEED = 7.5
const Walk_SPEED = 5.0
const JUMP_VELOCITY = 4.5
const RAY_LENGTH = 1000

@export var CAMERA_SPEED = 0.01
@onready var camera := $Camera
@onready var player := $"."
@onready var camera3d := $Camera/Camera3D
@onready var target = $Control/target
@onready var CTR = $Shader/ColorRect
@onready var ray =	$RayCast3D
@onready var img1 = $"Camera/open book/img1"
@onready var img2 = $"Camera/open book/img2"
@onready var img3 = $"Camera/open book/img3"
@onready var img4 = $"Camera/open book/img4"
@onready var img5 = $"Camera/open book/img5"
@onready var img6 = $"Camera/open book/img6"

var is_going = false
var num = 0
var img_num
var thread := Thread.new() 
const freq = 2.0
const amp = 0.08
var t = 0.0
var cam_walk = false
var not_book = true
var visto = false

func _ready():
	#CTR.transform.x = get_viewport().size.x
	#CTR.transform.y = get_viewport().size.y
	
	target.position.x = get_viewport().size.x / 2 - 626.0 / 2
	target.position.y = get_viewport().size.y / 2 - 470.0 / 2
	


# se vede un qualsiasi input
func _unhandled_input(event: InputEvent) -> void:
	# cattura il mouse in modo che non si vede
	if event is InputEventMouseButton: 
		Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
	# mostra di nuovo il mouse
	elif event.is_action_pressed("ui_cancel"):
		Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
	if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
		if event is InputEventMouseMotion:
			camera.rotate_y(-event.relative.x * CAMERA_SPEED)
			camera3d.rotate_x(-event.relative.y * CAMERA_SPEED)
			camera3d.rotation.x = clamp(camera3d.rotation.x, deg_to_rad(-50), deg_to_rad(60))
	
	# prepara la fotocamera con la animazione
	if event.is_action_pressed("fotocamera") and not_book:
		is_going = true
		$AnimPlayer.play('camera_anim')
		cam_walk = true
	# fa tornare indietro la fotocamera
	if event.is_action_released("fotocamera") and not_book:
		$AnimPlayer.play_backwards('camera_anim')
		is_going = false
		cam_walk = false
	# fa la foto
	if event.is_action_pressed('screenshot') and is_going and not_book:
			$Control/target.set_visible(false)#ui che voglio togliere
			if $AnimPlayer.is_playing() == false:
				await get_tree().process_frame
				await get_tree().process_frame
				print('target'+str($Control/target.is_visible()))
				#$Shader/CTR.set_visible(false)
				take_screenshot()
				$AnimPlayer2.play('scatto')
			$Control/target.set_visible(true)
			print('ciao')
	# apre il libro
	if Input.is_action_just_pressed('book'):
		if not_book:
			$AnimPlayer3.play('look_book')
			not_book = false
		else:
			$AnimPlayer3.play_backwards("look_book")
			not_book = true
			
			

	#questo serve per fare la foto
func take_screenshot() -> void:
	$Control/target.set_visible(false)
	# prende lo screenshot di quello che si vede come texure credo...
	var img = get_viewport().get_texture().get_image()
	var img_num = str(num)
	if visto:
		num += 1
	var file_path = "res://screenshot/image" + img_num + ".png"
	print(num)
	var img_copy := img.duplicate()
	# usa un thread per salvare la foto senza laggare
	var thread := Thread.new()
	# non so che cazzo e callable me la detto chatgbt:)
	var callable := func(): _save_image(img_copy, "res://screenshot/image" + img_num + ".png")
	thread.start(callable)
	print('img')
	
func _save_image(img: Image, path: String) -> void:
	if visto and num<=6:
		img.save_png(path)
		# per far vedere nel libro
		var image = Image.load_from_file(path)
		var texture = ImageTexture.create_from_image(image)
		if num == 1:
			img1.texture = texture
		elif num == 2:
			img2.texture = texture
		elif num == 3:
			img3.texture = texture
		elif num == 4:
			img4.texture = texture
		elif num == 5:
			img5.texture = texture
		elif num == 6:
			img6.texture = texture
		
		#apply_texture($"Camera/open book/Img1", path)
		print('save')
		
#func apply_texture(mesh_instance_node, texture_path):
	#var texture = ImageTexture.new()
	#var image = Image.new()
	#image.load(texture_path)
	#texture.create_from_image(image)
	#if mesh_instance_node.material_override:
		#mesh_instance_node.material_override.albedo_texture = texture

func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_gravity() * delta 

	# Handle jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement/deceleration.
	# As good practice, you should replace UI actions with custom gameplay actions.
	var input_dir := Input.get_vector("left", "right", "up", "down")
	var direction = (camera.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
	if Input.is_action_pressed("RUN") and is_on_floor()  and cam_walk == false:
		if direction:
			velocity.x = direction.x * Run_SPEED
			velocity.z = direction.z * Run_SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, Run_SPEED)
			velocity.z = move_toward(velocity.z, 0, Run_SPEED)
		
	elif Input.is_action_pressed("fotocamera"):
		if direction:
			velocity.x = direction.x * camera_SPEED
			velocity.z = direction.z * camera_SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, camera_SPEED)
			velocity.z = move_toward(velocity.z, 0, camera_SPEED)
		
		
	else:
		if direction:
			velocity.x = direction.x * Walk_SPEED
			velocity.z = direction.z * Walk_SPEED
		else:
			velocity.x = move_toward(velocity.x, 0, Walk_SPEED)
			velocity.z = move_toward(velocity.z, 0, Walk_SPEED)

	t += delta * velocity.length() * float(is_on_floor())
	camera.transform.origin = _headbob(t)
	
	
	move_and_slide()

func _headbob(time) -> Vector3:
	var pos = Vector3.ZERO
	pos.y = sin(time * freq)  * amp+ 1.626
	pos.x = cos(time * freq / 2) * amp
	return pos


func _on_timer_timeout() -> void:
	if not ray.is_colliding():
		visto = true
		print('visto')
	else: 
		visto=false
		print('non visto')

 
#func _on_anim_player_animation_finished(look_book) -> void:
#	not_book = true
#	print('finito')

# controlla se il gruppo ORB (non mi ricordo come si chiama lol) visibile 
func _on_visible_entrato() -> void:

	var focus = get_tree().get_nodes_in_group("punti focus")
	var nearest_spawn_point = focus[0]
	for focu in focus:
		if focu.global_position.distance_to(player.global_position) < nearest_spawn_point.global_position.distance_to(player.global_position):
			nearest_spawn_point = focu
	
	# usa ray per capire se e visibile (potrebbe essere un problema se ci sono tanti ORB)
	ray.set_target_position(nearest_spawn_point.position)
	$Timer.start()
	if not ray.is_colliding():
		visto = true
		print('visto')
	else: visto=false

func _on_visible_uscito() -> void:
	visto = false
	$Timer.stop()
	print('non visto')
