"""
Track 06: NATURE'S CALL - 3D Fractal Tree (L-System)
"""

import bpy
import math
import random
import sys
import os
from mathutils import Vector, Matrix

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utils import *


def create_branch(start, end, thickness=0.05, name="Branch"):
    """Create a cylindrical branch between two points."""
    direction = Vector(end) - Vector(start)
    length = direction.length
    
    if length < 0.01:
        return None
    
    # Create cylinder
    bpy.ops.mesh.primitive_cylinder_add(
        radius=thickness,
        depth=length,
        location=(0, 0, 0)
    )
    branch = bpy.context.active_object
    branch.name = name
    
    # Position and orient
    mid = [(start[i] + end[i]) / 2 for i in range(3)]
    branch.location = mid
    
    # Rotate to align with direction
    up = Vector((0, 0, 1))
    direction.normalize()
    
    rotation_axis = up.cross(direction)
    if rotation_axis.length > 0.0001:
        rotation_axis.normalize()
        angle = math.acos(max(-1, min(1, up.dot(direction))))
        branch.rotation_mode = 'AXIS_ANGLE'
        branch.rotation_axis_angle = (angle, rotation_axis.x, rotation_axis.y, rotation_axis.z)
    
    return branch


def generate_tree_recursive(start, direction, length, depth, max_depth, branches, leaves):
    """Recursively generate tree branches."""
    if depth > max_depth or length < 0.1:
        # Add leaf
        leaves.append(start)
        return
    
    end = [start[i] + direction[i] * length for i in range(3)]
    branches.append((start, end, depth))
    
    # Generate child branches
    angles = [math.pi/5, -math.pi/5, math.pi/6, -math.pi/6]
    
    for angle in angles:
        if random.random() > 0.35:
            # Rotate direction around random axis
            rot_axis = (random.uniform(-1, 1), random.uniform(-1, 1), 0)
            norm = math.sqrt(sum(r*r for r in rot_axis))
            if norm > 0.01:
                rot_axis = tuple(r/norm for r in rot_axis)
            else:
                rot_axis = (1, 0, 0)
            
            # Simple rotation (approximate)
            new_dir = [
                direction[0] * math.cos(angle) + rot_axis[0] * (1 - math.cos(angle)),
                direction[1] * math.cos(angle) + rot_axis[1] * (1 - math.cos(angle)),
                direction[2] * math.cos(angle) + math.sin(angle) * 0.3 + 0.3
            ]
            
            # Normalize
            norm = math.sqrt(sum(d*d for d in new_dir))
            new_dir = [d/norm for d in new_dir]
            
            generate_tree_recursive(end, new_dir, length * 0.7, depth + 1, max_depth, branches, leaves)


def create_natures_call_animation():
    """Create the full Track 06 animation."""
    clear_scene()
    setup_scene(background_color=(0.02, 0.11, 0.09, 1.0))  # Forest dark green
    
    # Create camera
    camera = create_camera(location=(0, -15, 5), rotation=(1.2, 0, 0))
    animate_camera_orbit(camera, center=(0, 0, 2), radius=15, height=5,
                        start_frame=1, end_frame=TOTAL_FRAMES, revolutions=0.3)
    
    # Generate tree structure
    branches = []
    leaves = []
    
    start = (0, 0, -4)
    direction = (0, 0, 1)
    generate_tree_recursive(start, direction, 2.0, 0, 5, branches, leaves)
    
    # Create branch objects with progressive animation
    branch_mat = create_emission_material("BranchMat", COLORS["natures_call"], strength=1.5)
    branch_objects = []
    
    total_branches = len(branches)
    frames_per_branch = max(1, 400 // total_branches)
    
    for i, (start_pos, end_pos, depth) in enumerate(branches):
        thickness = max(0.02, 0.1 - depth * 0.015)
        
        # Create curve instead of cylinder for smoother look
        curve_data = bpy.data.curves.new(name=f"Branch_{i}", type='CURVE')
        curve_data.dimensions = '3D'
        curve_data.bevel_depth = thickness
        curve_data.bevel_resolution = 4
        
        spline = curve_data.splines.new('BEZIER')
        spline.bezier_points.add(1)
        spline.bezier_points[0].co = start_pos
        spline.bezier_points[0].handle_right = [start_pos[j] + (end_pos[j] - start_pos[j]) * 0.3 for j in range(3)]
        spline.bezier_points[0].handle_left = start_pos
        spline.bezier_points[1].co = end_pos
        spline.bezier_points[1].handle_left = [end_pos[j] - (end_pos[j] - start_pos[j]) * 0.3 for j in range(3)]
        spline.bezier_points[1].handle_right = end_pos
        
        branch_obj = bpy.data.objects.new(f"Branch_{i}", curve_data)
        bpy.context.collection.objects.link(branch_obj)
        branch_obj.data.materials.append(branch_mat)
        
        # Animate growth (bevel depth)
        appear_frame = 30 + i * frames_per_branch
        
        curve_data.bevel_depth = 0.0
        curve_data.keyframe_insert(data_path="bevel_depth", frame=1)
        curve_data.keyframe_insert(data_path="bevel_depth", frame=appear_frame)
        
        curve_data.bevel_depth = thickness
        curve_data.keyframe_insert(data_path="bevel_depth", frame=appear_frame + 20)
        
        branch_objects.append(branch_obj)
    
    # Create leaves
    leaf_mat = create_emission_material("LeafMat", (0.133, 0.773, 0.333, 1.0), strength=2.0)
    leaf_objects = []
    
    leaves_appear_frame = 450
    
    for i, pos in enumerate(leaves[:80]):  # Limit leaves
        bpy.ops.mesh.primitive_ico_sphere_add(radius=0.12, subdivisions=1, location=pos)
        leaf = bpy.context.active_object
        leaf.name = f"Leaf_{i:03d}"
        leaf.data.materials.append(leaf_mat)
        
        # Animate leaf appearance
        keyframe_scale(leaf, 1, 0.01)
        keyframe_scale(leaf, leaves_appear_frame + i * 2, 0.01)
        keyframe_scale(leaf, leaves_appear_frame + i * 2 + 30, 1.0)
        
        leaf_objects.append(leaf)
    
    return branch_objects, leaf_objects


if __name__ == "__main__":
    create_natures_call_animation()
    
    output_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    bpy.ops.wm.save_as_mainfile(filepath=os.path.join(output_dir, "exports", "track06_natures_call.blend"))
    
    bpy.ops.export_scene.gltf(
        filepath=os.path.join(output_dir, "exports", "track06_natures_call.gltf"),
        export_animations=True,
        export_format='GLTF_SEPARATE'
    )
    
    bpy.ops.wm.alembic_export(
        filepath=os.path.join(output_dir, "exports", "track06_natures_call.abc"),
        start=1, end=TOTAL_FRAMES
    )
    
    print("Track 06 - Nature's Call: Export complete!")
