class_name TreeNode
extends Node3D

var tree_data: TreeDataResource
var model_instance: Node3D
var mesh_instances: Array[MeshInstance3D] = []
var original_materials: Array[Material] = []
var outline_material: Material
var is_invisible: bool = false
var interact_range: bool = false
var fade_tween: Tween

@onready var area: Area3D = $InteractRange
@onready var last_blocked: Timer = $LastBlocked

func _ready():
	setup_outline_material()
	area.body_entered.connect(_on_player_entered)
	area.body_exited.connect(_on_player_exited)
	last_blocked.timeout.connect(_on_fade_timer_timeout)

func set_tree_data(data: TreeDataResource):
	tree_data = data
	spawn_model()

func spawn_model():
	if not tree_data or not tree_data.model:
		Log.pr("No tree data or model provided")
		return
	
	# Clear any existing model
	if model_instance:
		model_instance.queue_free()
		mesh_instances.clear()
		original_materials.clear()
	
	# Instantiate the model from the TreeDataResource
	model_instance = tree_data.model.instantiate()
	tree_data.apply_seasonal_colors(model_instance, Season.current)
	add_child(model_instance)
	
	# Re-scan for mesh instances in the new model
	find_all_mesh_instances(model_instance)
	
	# Apply any additional properties from tree_data
	apply_tree_properties()

func apply_tree_properties():
	if not model_instance or not tree_data:
		return
	
	# Apply scale variations if defined in tree_data
	if tree_data.has_method("get_random_scale"):
		model_instance.scale *= tree_data.get_random_scale()
	
	# Apply random scale based on tree properties
	if tree_data.max_height > 0:
		var scale_variation = randf_range(1.5, 2)
		model_instance.scale *= scale_variation

func setup_outline_material() -> void:
	# Create outline material with your shader
	outline_material = ShaderMaterial.new()
	outline_material.shader = preload("res://Common/shaders/outline.gdshader")
	outline_material.set_shader_parameter("color", Vector3(0.702, 0.557, 0.259))

func find_all_mesh_instances(node: Node):
	if node is MeshInstance3D:
		mesh_instances.append(node)
	for child in node.get_children():
		find_all_mesh_instances(child)

func fade_out_tree_simple(duration: float = 0.25):
	# Reset the timer
	last_blocked.stop()
	last_blocked.start()
	
	if is_invisible or interact_range:
		return

	is_invisible = true
	
	# Kill any existing fade tween
	if fade_tween:
		fade_tween.kill()
	
	for mesh_instance in mesh_instances:
		fade_mesh_materials(mesh_instance, 1.0, 0.1, duration)

# This gets called when the timer times out
func _on_fade_timer_timeout():
	fade_in_tree_immediate()

func fade_in_tree_immediate(duration: float = 0.25):
	if not is_invisible:
		return
	
	# Kill any existing fade tween
	if fade_tween:
		fade_tween.kill()
	
	for mesh_instance in mesh_instances:
		fade_mesh_materials(mesh_instance, 0.1, 1.0, duration)
	
	is_invisible = false

func fade_mesh_materials(mesh_instance: MeshInstance3D, from_alpha: float, to_alpha: float, duration: float):
	if not mesh_instance.mesh:
		return

	var surface_count = mesh_instance.mesh.get_surface_count()

	for surface_id in range(surface_count):
		var material = mesh_instance.get_surface_override_material(surface_id)
		
		# Always ensure we have a unique material instance
		if not material:
				# No override material - duplicate from base material
				var base_material = mesh_instance.mesh.surface_get_material(surface_id)
				if base_material:
						material = base_material.duplicate()
						mesh_instance.set_surface_override_material(surface_id, material)
		else:
				# Override material exists - duplicate it to ensure uniqueness
				material = material.duplicate()
				mesh_instance.set_surface_override_material(surface_id, material)
		
		# Only work with StandardMaterial3D
		if material and material is StandardMaterial3D:
				var std_mat = material as StandardMaterial3D
				
				# Set transparency mode based on target alpha
				if to_alpha < 1.0:
						std_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
				
				# Force shadow casting
				mesh_instance.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
				
				# Set initial alpha
				std_mat.albedo_color.a = from_alpha
				
				# Create and store the tween
				fade_tween = create_tween()
				fade_tween.tween_method(
						func(alpha: float):
								std_mat.albedo_color.a = alpha,
						from_alpha, to_alpha, duration
				)
				
				# When fading to full opacity, reset transparency mode
				if to_alpha >= 1.0:
						fade_tween.tween_callback(
								func(): std_mat.transparency = BaseMaterial3D.TRANSPARENCY_DISABLED
						)
						
func toggle_tree_visibility(duration: float = 1.0):
	if is_invisible:
		fade_in_tree_immediate(duration)
	else:
		fade_out_tree_simple(duration)

func _on_player_entered(body: Node3D):
	if body.is_in_group("player"):
		# Apply outline to all mesh instances
		interact_range = true
		if not is_invisible:
			for mesh in mesh_instances:
				mesh.material_overlay = outline_material

func _on_player_exited(body: Node3D):
	if body.is_in_group("player"):
		interact_range = false
		# Remove outline from all mesh instances
		if not is_invisible:
			# Reset the material overlay to null
			for mesh in mesh_instances:
				mesh.material_overlay = null
