class_name EnvironmentManagerRoot
extends Node3D

@export var environment_config: EnvironmentConfig

@export_group("Camera")
@export var camera: Camera3D
@export var camera_pivot: Node3D

@export_group("Particles")
@export var particles_wind: GPUParticles3D
@export var particles_snow: GPUParticles3D
@export var particles_fireflies: GPUParticles3D
@export var particles_rain: GPUParticles3D
@export var godray: PackedScene
@export var environment_dust: ColorRect
@export var blur: ColorRect
@export var environment_shadows: MeshInstance3D

@export_group("Sound")
@export var thunder_sounds: Array[AudioStream]
@export var rain_sounds: Array[AudioStream]

#environment nodes
@onready var sun: DirectionalLight3D = $"../DirectionalLight3D"
@onready var environment: WorldEnvironment = $"../WorldEnvironment"

var day_night_controller: DayNightController 
var weather_controller: WeatherController

var day_tween: Tween
var day_time: float = 0.0

func _ready() -> void:
	
	#set noise texture 2d to materials in special group
	ApplyWindNoiseToMaterials()
	#set weather overlay (snow + rain) to materials in special group
	ApplyWeatherShaderToMaterials()
		
	if day_night_controller == null:
		day_night_controller = DayNightController.new(
			environment_config
		)
		day_night_controller.name = "DayNightController"
		day_night_controller.time_changed.connect(select_day_time)
		add_child(day_night_controller)

	if weather_controller == null:
		weather_controller = WeatherController.new(
			particles_wind,
			particles_snow,
			particles_fireflies,
			particles_rain,
			godray,
			environment_dust,
			blur,
			environment_shadows,
			sun,
			environment,
			environment_config,
			camera,
			camera_pivot,
			thunder_sounds,
			rain_sounds
		)
		weather_controller.name = "WeatherController"
		add_child(weather_controller)

func ApplyWindNoiseToMaterials():
	var noise_tex = preload("res://core/daynight/noise.tres")
	for node in get_tree().get_nodes_in_group("wind_node"):
		_apply_wind_noise_to_node(node, noise_tex)

func _apply_wind_noise_to_node(node: Node, noise_tex: Texture2D) -> void:
	if node is GeometryInstance3D:
		var material_override := node.material_override as ShaderMaterial
		if material_override:
			material_override.set_shader_parameter("wind_noise", noise_tex)

		if node is MeshInstance3D:
			for surface_index in node.get_surface_override_material_count():
				var surface_material := node.get_surface_override_material(surface_index) as ShaderMaterial
				if surface_material:
					surface_material.set_shader_parameter("wind_noise", noise_tex)

	for child in node.get_children():
		_apply_wind_noise_to_node(child, noise_tex)

func ApplyWeatherShaderToMaterials():
	var weather_shader = preload("res://core/daynight/weather_overlay.tres")

	for node in get_tree().get_nodes_in_group("weather_node"):
		if node is GeometryInstance3D:
			node.material_overlay = weather_shader
		else:
			for child in node.get_children():
				if child is GeometryInstance3D:
					child.material_overlay = weather_shader

func select_day_time(normalized_time: float) -> void:
	#set show_day_time_debug = true to show debug on screen
	#normalized_time is a value between 0 and 1; the time of the day is calculate as "normalized_time" * 1440; day_time is the step to pass from sunrise, to day, to sunset, to night
	#e.g.
	#Time		normalized_time		day_time
	#00:00		0.0000				3.0
	#06:00		0.2500				1.0
	#09:36		0.4000				1.75
	#10:48		0.4500				2.0
	#12:00		0.5000				2.0
	#19:12		0.8000				2.0
	#21:36		0.9000				2.5
	#24:00		1.0000				3.0
	
	if normalized_time < environment_config.sunrise:
		#Sunrise: night → morning
		day_time = 3.0 - (normalized_time / environment_config.sunrise) * 2.0  # 3.0 → 1.0
	elif normalized_time < environment_config.day:
		#Morning: morning → afternoon
		var t: float =  (normalized_time - environment_config.sunrise) / (environment_config.day - environment_config.sunrise)
		day_time = 1.0 + t  # 1.0 → 2.0
	elif normalized_time < environment_config.sunset:
		#Broad daylight
		day_time = 2.0
	elif normalized_time < environment_config.night:
		#Sunset: afternoon → night
		var t: float = (normalized_time - environment_config.sunset) / (environment_config.night - environment_config.sunset)
		day_time = 2.0 + t  # 2.0 → 3.0
	else:
		#Night
		day_time = 3.0

	if weather_controller:
		weather_controller.day_time = day_time
