extends Node3D

@export_group("Luce Direzionale e Ambiente")
@export var color_mattina: Color = Color(1.0, 0.9, 0.8, 1.0)
@export var color_pomeriggio: Color = Color(1.0, 0.6, 0.2, 1.0)
@export var color_notte: Color = Color(0.1, 0.1, 0.3, 1.0)

@export_group("Colori Cielo - Alto (Top)")
@export var sky_top_mattina: Color = Color(0.35, 0.65, 0.9, 1.0)
@export var sky_top_pomeriggio: Color = Color(0.7, 0.45, 0.2, 1.0)
@export var sky_top_notte: Color = Color(0.05, 0.05, 0.15, 1.0)

@export_group("Colori Cielo - Orizzonte (Horizon)")
@export var sky_horizon_mattina: Color = Color(0.75, 0.85, 0.95, 1.0)
@export var sky_horizon_pomeriggio: Color = Color(0.95, 0.65, 0.35, 1.0)
@export var sky_horizon_notte: Color = Color(0.15, 0.1, 0.25, 1.0)

@export_group("Ciclo Temporale")
@export_range(1.0, 3.0) var tempo_giorno: float = 1.0
@export var durata_transizione: float = 3.0 
@export_range(0.0, 1.0) var energia_luce_notte: float = 0.3

@export_group("Materiali Extra")
@export var materiale_nebbia: ShaderMaterial
@export var materiale_pioggia_gocce: StandardMaterial3D 
@export var materiale_nuvole: ShaderMaterial 
@export var nodo_polvere: ColorRect

@export_group("Meteo (Pioggia & Fulmini)")
@export var colore_mood_pioggia: Color = Color(0.5, 0.6, 0.7, 1.0)
@export var tempo_min_fulmine: float = 5.0 
@export var tempo_max_fulmine: float = 15.0
@export var colore_fulmine: Color = Color(1.0, 1.0, 0.8, 1.0)
@export var fulmini_min: int = 1
@export var fulmini_max: int = 3
@export var scala_min_fulmine: float = 1.0
@export var scala_max_fulmine: float = 3.0

@export_group("Cinematic Mode Ambiente")
@export var intervallo_eventi_meteo: float = 8.0 

@export_group("God Rays")
@export var godray_scene: PackedScene
@export var max_rain_godrays: int = 8
@export var godray_spawn_radius: float = 15.0
@export var godray_spawn_offset: Vector3 = Vector3(15.0, 5.0, -15.0) 
@export var godray_rotation_degrees: Vector3 = Vector3(-45.0, 45.0, -30.0) 
@export var godray_spawn_height: float = 5.0 
@export var godray_scale: Vector3 = Vector3(2.0, 6.0, 2.0)

@export_group("Lucciole")
@export var particelle_lucciole: GPUParticles3D
@export var quantita_lucciole: int = 60
@export var raggio_spawn_lucciole: float = 20.0
@export var altezza_spawn_lucciole: float = 3.0 

@export_group("Vento")
@export var particelle_vento: GPUParticles3D
@export var quantita_vento: int = 100
@export var raggio_spawn_vento: float = 25.0
@export var altezza_spawn_vento: float = 5.0

# --- GRUPPO NEVE AGGIORNATO ---
@export_group("Neve")
@export var bottone_neve: Button
@export var bottone_nevicata: Button
@export var overlay_nebbia_schermo: ColorRect
@export var particelle_neve: GPUParticles3D
@export var quantita_neve: int = 2000
@export var tempo_transizione_neve: float = 10.0

@onready var sole: DirectionalLight3D = $DirectionalLight3D
@onready var ambiente: WorldEnvironment = $WorldEnvironment
@onready var menu_giornata: OptionButton = $CanvasLayer/OptionButton 
@onready var bottone_pioggia: CheckButton = $CanvasLayer/CheckButtonPioggia
@onready var particelle_pioggia: GPUParticles3D = $SubViewportContainer/SubViewport/World/Camere/PioggiaCadente
@onready var nodo_camere: Node3D = $SubViewportContainer/SubViewport/World/Camere
@onready var luce_lampo: DirectionalLight3D = $LuceLampo
@onready var sprite_fulmine: Sprite3D = $SubViewportContainer/SubViewport/World/Camere/SpriteFulmine

var tween_giorno: Tween
var is_raining: bool = false
var intensita_pioggia: float = 0.0 
var timer_prossimo_fulmine: float = 0.0

var is_cinematic_mode: bool = false
var timer_cinematic_env: float = 0.0
var sto_cambiando_in_cinematic: bool = false 

# Variabili di stato per la neve
var is_snow_accumulated: bool = false 
var is_actively_snowing: bool = false
var snow_tween: Tween
var cold_tween: Tween
var actual_snow_amount: float = 0.0

func _ready() -> void:
	if menu_giornata:
		menu_giornata.clear()
		menu_giornata.add_item("1 - Mattina")
		menu_giornata.add_item("2 - Pomeriggio")
		menu_giornata.add_item("3 - Notte")
		menu_giornata.selected = int(tempo_giorno) - 1
		menu_giornata.item_selected.connect(_on_giornata_selezionata)
	
	if bottone_pioggia:
		bottone_pioggia.toggled.connect(_on_pioggia_toggled)
		
	if particelle_pioggia:
		particelle_pioggia.emitting = false
		
	# Inizializzazione Lucciole
	if particelle_lucciole:
		particelle_lucciole.emitting = false
		particelle_lucciole.amount = quantita_lucciole
		var proc_mat = particelle_lucciole.process_material as ParticleProcessMaterial
		if proc_mat:
			proc_mat.emission_box_extents = Vector3(raggio_spawn_lucciole, altezza_spawn_lucciole, raggio_spawn_lucciole)
			
	# Inizializzazione Vento
	if particelle_vento:
		particelle_vento.emitting = false
		particelle_vento.amount = quantita_vento
		var proc_mat_vento = particelle_vento.process_material as ParticleProcessMaterial
		if proc_mat_vento:
			proc_mat_vento.emission_box_extents = Vector3(raggio_spawn_vento, altezza_spawn_vento, raggio_spawn_vento)
			
	# --- INIZIALIZZAZIONE NEVE ---
	set_snow_amount(0.0)
	
	if particelle_neve:
		particelle_neve.emitting = false
		particelle_neve.amount = quantita_neve
		
	if bottone_neve:
		bottone_neve.pressed.connect(_on_snow_button_pressed)
	
	if bottone_nevicata:
		bottone_nevicata.pressed.connect(_on_nevicata_button_pressed)
		bottone_nevicata.disabled = true
		
	_resetta_timer_fulmine()

func _input(event: InputEvent) -> void:
	if event is InputEventKey and event.pressed and not event.echo:
		if event.keycode == KEY_C:
			is_cinematic_mode = !is_cinematic_mode
			if is_cinematic_mode:
				timer_cinematic_env = intervallo_eventi_meteo 
				print("Ambiente Cinematic: ATTIVATA")
			else:
				print("Ambiente Cinematic: DISATTIVATA")
			return
			
		if event.keycode in [KEY_1, KEY_2, KEY_3, KEY_4, KEY_5]:
			if is_cinematic_mode:
				is_cinematic_mode = false
				print("Ambiente Cinematic: DISATTIVATA (Cambio camera manuale)")

func _on_giornata_selezionata(index: int) -> void:
	if not sto_cambiando_in_cinematic and is_cinematic_mode:
		is_cinematic_mode = false
		print("Ambiente Cinematic: DISATTIVATA (Orario cambiato manualmente)")
		
	var target_tempo = float(index + 1)
	if tween_giorno and tween_giorno.is_valid():
		tween_giorno.kill()
	tween_giorno = create_tween()
	tween_giorno.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
	tween_giorno.tween_property(self, "tempo_giorno", target_tempo, durata_transizione)
	
	if index == 0:
		trigger_morning()

func _on_pioggia_toggled(toggled_on: bool) -> void:
	if not sto_cambiando_in_cinematic and is_cinematic_mode:
		is_cinematic_mode = false
		print("Ambiente Cinematic: DISATTIVATA (Pioggia cambiata manualmente)")
		
	var stava_piovendo = is_raining 
	is_raining = toggled_on
	if particelle_pioggia:
		particelle_pioggia.emitting = is_raining
		
	if stava_piovendo and not is_raining:
		trigger_after_rain()

func _process(delta: float) -> void:
	if is_cinematic_mode:
		timer_cinematic_env -= delta
		if timer_cinematic_env <= 0.0:
			_genera_evento_meteo_casuale()
			timer_cinematic_env = randf_range(intervallo_eventi_meteo * 0.8, intervallo_eventi_meteo * 1.5)
			
	var base_tint: Color
	var base_sky_top: Color
	var base_sky_horizon: Color
	
	if is_raining:
		intensita_pioggia = move_toward(intensita_pioggia, 1.0, delta * 0.5)
		
		timer_prossimo_fulmine -= delta
		if timer_prossimo_fulmine <= 0.0:
			_scatena_fulmine()
			_resetta_timer_fulmine()
	else:
		intensita_pioggia = move_toward(intensita_pioggia, 0.0, delta * 0.5)
		
	if materiale_nuvole:
		var densita_attuale = lerp(0.4, 1.0, intensita_pioggia)
		materiale_nuvole.set_shader_parameter("cloud_density", densita_attuale)
		var sharpness_attuale = lerp(0.14, 0.0, intensita_pioggia)
		materiale_nuvole.set_shader_parameter("center_sharpness", sharpness_attuale)
	
	if tempo_giorno <= 2.0:
		var t = tempo_giorno - 1.0
		base_tint = color_mattina.lerp(color_pomeriggio, t)
		base_sky_top = sky_top_mattina.lerp(sky_top_pomeriggio, t)
		base_sky_horizon = sky_horizon_mattina.lerp(sky_horizon_pomeriggio, t)
	else:
		var t = tempo_giorno - 2.0
		base_tint = color_pomeriggio.lerp(color_notte, t)
		base_sky_top = sky_top_pomeriggio.lerp(sky_top_notte, t)
		base_sky_horizon = sky_horizon_pomeriggio.lerp(sky_horizon_notte, t)
		
	var final_tint = base_tint.lerp(base_tint * colore_mood_pioggia, intensita_pioggia)
	var final_sky_top = base_sky_top.lerp(base_sky_top * colore_mood_pioggia, intensita_pioggia)
	var final_sky_horizon = base_sky_horizon.lerp(base_sky_horizon * colore_mood_pioggia, intensita_pioggia)
		
	var night_val = clamp(tempo_giorno - 2.0, 0.0, 1.0)
	var colore_riflesso = Color(0.4, 0.5, 0.6, 1.0)
	var colore_gocce = final_sky_horizon.lerp(colore_riflesso, 0.15)
	colore_gocce = colore_gocce.lerp(colore_gocce * 0.4, night_val)
	
	if materiale_pioggia_gocce:
		materiale_pioggia_gocce.albedo_color = colore_gocce

	if sole:
		sole.light_color = final_tint
		var target_energy = lerp(1.0, energia_luce_notte, night_val)
		sole.light_energy = lerp(target_energy, target_energy * 0.4, intensita_pioggia)
		
	if ambiente and ambiente.environment:
		ambiente.environment.ambient_light_color = final_tint
		ambiente.environment.fog_light_color = final_sky_horizon
		
		var sky_mat = ambiente.environment.sky.sky_material as ShaderMaterial
		if sky_mat:
			sky_mat.set_shader_parameter("sky_top_color", final_sky_top)
			sky_mat.set_shader_parameter("sky_horizon_color", final_sky_horizon)
			sky_mat.set_shader_parameter("sun_color", final_tint)
			sky_mat.set_shader_parameter("night_intensity", night_val)
			
		if materiale_nebbia:
			materiale_nebbia.set_shader_parameter("night_intensity", night_val)
			materiale_nebbia.set_shader_parameter("sun_color", final_tint)

	# ==========================================
	# --- GESTIONE POLVERE, LUCCIOLE E VENTO ---
	# ==========================================
	var e_notte = tempo_giorno >= 2.5
	
	# Polvere (2D): Solo di giorno e senza pioggia
	if nodo_polvere:
		if not is_raining and not e_notte:
			nodo_polvere.visible = true
		else:
			nodo_polvere.visible = false
			
	# Lucciole (3D): Solo di notte e senza pioggia
	if particelle_lucciole:
		if not is_raining and e_notte:
			particelle_lucciole.emitting = true
		else:
			particelle_lucciole.emitting = false
			
	# Vento (3D): Solo di giorno e senza pioggia
	if particelle_vento:
		if not is_raining and not e_notte:
			particelle_vento.emitting = true
		else:
			particelle_vento.emitting = false

func _genera_evento_meteo_casuale() -> void:
	sto_cambiando_in_cinematic = true 
	
	var scelta = randi() % 3
	
	if scelta == 0:
		var nuovo_orario = randi() % 3
		if menu_giornata:
			menu_giornata.selected = nuovo_orario
		_on_giornata_selezionata(nuovo_orario)
		
	elif scelta == 1:
		var piove = randf() > 0.5
		if bottone_pioggia:
			bottone_pioggia.set_pressed_no_signal(piove)
		_on_pioggia_toggled(piove)
		
	elif scelta == 2:
		if not is_raining:
			if bottone_pioggia:
				bottone_pioggia.set_pressed_no_signal(true)
			_on_pioggia_toggled(true)
		_scatena_fulmine()
		
	sto_cambiando_in_cinematic = false 

func _resetta_timer_fulmine() -> void:
	timer_prossimo_fulmine = randf_range(tempo_min_fulmine, tempo_max_fulmine)

func _scatena_fulmine() -> void:
	if luce_lampo:
		var tween_luce = create_tween()
		luce_lampo.light_energy = 5.0
		
		tween_luce.tween_interval(0.05)
		tween_luce.tween_callback(func(): luce_lampo.light_energy = 0.0)
		tween_luce.tween_interval(0.05)
		tween_luce.tween_callback(func(): luce_lampo.light_energy = 2.0)
		tween_luce.tween_method(func(val): luce_lampo.light_energy = val, 2.0, 0.0, 0.2)

	var numero_scariche = randi_range(fulmini_min, fulmini_max)
	
	for i in numero_scariche:
		if sprite_fulmine:
			var angolo_casuale = randf() * TAU 
			var distanza = randf_range(10.0, 40.0) 
			
			sprite_fulmine.position = Vector3(cos(angolo_casuale) * distanza, 10.0, sin(angolo_casuale) * distanza)
			
			sprite_fulmine.modulate = colore_fulmine
			sprite_fulmine.modulate.a = 1.0 
			
			var s = randf_range(scala_min_fulmine, scala_max_fulmine)
			sprite_fulmine.scale = Vector3(s, s, s)
			
			var tween_sprite = create_tween()
			tween_sprite.tween_interval(0.2) 
			tween_sprite.tween_property(sprite_fulmine, "modulate:a", 0.0, 0.4)
		
		if numero_scariche > 1:
			await get_tree().create_timer(randf_range(0.05, 0.15)).timeout

func trigger_morning() -> void:
	spawn_single_godray()

func trigger_after_rain() -> void:
	if tempo_giorno < 2.5:
		for i in range(max_rain_godrays):
			spawn_single_godray()

func spawn_single_godray() -> void:
	if godray_scene == null:
		print("Attenzione: Manca la scena del Godray nell'Inspector!")
		return
	if nodo_camere == null:
		print("Attenzione: Non trovo il nodo Camere per agganciare il Godray!")
		return
		
	var ray = godray_scene.instantiate()
	
	var nodo_mondo = nodo_camere.get_parent()
	nodo_mondo.add_child(ray) 
	
	var random_x = randf_range(-godray_spawn_radius, godray_spawn_radius)
	var random_z = randf_range(-godray_spawn_radius, godray_spawn_radius)
	
	ray.global_position = nodo_camere.global_position + Vector3(random_x, godray_spawn_height, random_z)
	ray.rotation_degrees = godray_rotation_degrees
	ray.scale = godray_scale

# ==========================================
# --- LOGICA NEVE AGGIORNATA ---
# ==========================================

func _on_snow_button_pressed():
	is_snow_accumulated = !is_snow_accumulated
	
	# Sblocca il pulsante nevicata solo se c'è accumulo
	if bottone_nevicata:
		bottone_nevicata.disabled = !is_snow_accumulated
	
	# Se sciogliamo la neve, fermiamo anche la nevicata attiva
	if not is_snow_accumulated and is_actively_snowing:
		_on_nevicata_button_pressed()
	
	var target_snow: float = 1.0 if is_snow_accumulated else 0.0
	
	if snow_tween and snow_tween.is_valid():
		snow_tween.kill()
		
	snow_tween = create_tween()
	snow_tween.tween_method(set_snow_amount, actual_snow_amount, target_snow, tempo_transizione_neve)

func _on_nevicata_button_pressed():
	if not is_snow_accumulated:
		return
		
	is_actively_snowing = !is_actively_snowing
	
	if particelle_neve:
		particelle_neve.emitting = is_actively_snowing
		
	if overlay_nebbia_schermo and overlay_nebbia_schermo.material:
		var target_opacity: float = 1.0 if is_actively_snowing else 0.135
		var target_radius: float = 0.350 if is_actively_snowing else 0.465
		
		if cold_tween and cold_tween.is_valid():
			cold_tween.kill()
			
		cold_tween = create_tween()
		cold_tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN_OUT)
		cold_tween.set_parallel(true) 
		cold_tween.tween_property(overlay_nebbia_schermo.material, "shader_parameter/max_opacity", target_opacity, 4.0)
		cold_tween.tween_property(overlay_nebbia_schermo.material, "shader_parameter/clear_center_radius", target_radius, 4.0)

func set_snow_amount(value: float):
	actual_snow_amount = value 
	RenderingServer.global_shader_parameter_set("global_snow_amount", value)
