"""
Track 01: SKIN (INTRO) - Morphing Parametric Surface
"""

import bpy
import bmesh
import math
import sys
import os

# Add parent directory to path for utils
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from utils import *


def create_parametric_surface(u_segments=40, v_segments=40, t=0):
    """Create a morphing skin-like parametric surface."""
    mesh = bpy.data.meshes.new("SkinSurface")
    obj = bpy.data.objects.new("SkinSurface", mesh)
    bpy.context.collection.objects.link(obj)
    
    bm = bmesh.new()
    
    # Generate vertices
    verts = []
    for i in range(u_segments + 1):
        u = i / u_segments * math.pi
        row = []
        for j in range(v_segments + 1):
            v = j / v_segments * 2 * math.pi
            
            # Parametric equations with time-based morphing
            x = math.sin(u) * math.cos(v) * (1 + 0.2 * math.sin(3 * u + t))
            y = math.sin(u) * math.sin(v) * (1 + 0.2 * math.cos(3 * v + t))
            z = math.cos(u) + 0.3 * math.sin(3 * v + 2 * u + t)
            
            vert = bm.verts.new((x * 2, y * 2, z * 2))
            row.append(vert)
        verts.append(row)
    
    bm.verts.ensure_lookup_table()
    
    # Create faces
    for i in range(u_segments):
        for j in range(v_segments):
            v1 = verts[i][j]
            v2 = verts[i][j + 1]
            v3 = verts[i + 1][j + 1]
            v4 = verts[i + 1][j]
            try:
                bm.faces.new([v1, v2, v3, v4])
            except:
                pass
    
    bm.to_mesh(mesh)
    bm.free()
    
    # Add subdivision and smooth shading
    bpy.context.view_layer.objects.active = obj
    bpy.ops.object.shade_smooth()
    
    return obj


def create_skin_animation():
    """Create the full Track 01 animation."""
    clear_scene()
    setup_scene(background_color=COLORS["intro"])
    
    # Create camera
    camera = create_camera(location=(0, -8, 4), rotation=(1.2, 0, 0))
    animate_camera_orbit(camera, center=(0, 0, 0), radius=8, height=4, 
                        start_frame=1, end_frame=TOTAL_FRAMES, revolutions=0.5)
    
    # Create the morphing surface using shape keys
    base_surface = create_parametric_surface(t=0)
    
    # Add material
    mat = create_emission_material("SkinMaterial", COLORS["skin"], strength=1.5)
    base_surface.data.materials.append(mat)
    
    # Create shape keys for morphing animation
    base_surface.shape_key_add(name="Basis")
    
    # Create morph targets at different time values
    morph_frames = [1, 125, 250, 375, 500, 625, 750]
    
    for idx, frame in enumerate(morph_frames):
        t = idx * math.pi / 2
        
        # Create temporary mesh for this morph state
        temp = create_parametric_surface(t=t)
        
        # Add shape key from temp mesh
        sk = base_surface.shape_key_add(name=f"Morph_{idx}")
        
        # Copy vertex positions
        for i, vert in enumerate(temp.data.vertices):
            if i < len(sk.data):
                sk.data[i].co = vert.co
        
        # Delete temp object
        bpy.data.objects.remove(temp)
    
    # Animate shape keys
    for idx, frame in enumerate(morph_frames):
        for sk_idx in range(1, len(base_surface.data.shape_keys.key_blocks)):
            sk = base_surface.data.shape_keys.key_blocks[sk_idx]
            
            # Set value: 1.0 at matching frame, 0.0 at others
            if sk_idx == idx + 1:
                sk.value = 1.0
            else:
                sk.value = 0.0
            sk.keyframe_insert(data_path="value", frame=frame)
    
    # Add gentle rotation
    for frame in range(1, TOTAL_FRAMES + 1, 10):
        t = frame / TOTAL_FRAMES
        base_surface.rotation_euler = (0, 0, t * math.pi * 0.5)
        base_surface.keyframe_insert(data_path="rotation_euler", frame=frame)
    
    # Add entrance and exit animations
    keyframe_scale(base_surface, 1, 0.01)
    keyframe_scale(base_surface, 90, 1.0)
    keyframe_scale(base_surface, TOTAL_FRAMES - 30, 1.0)
    keyframe_scale(base_surface, TOTAL_FRAMES, 0.01)
    
    return base_surface


if __name__ == "__main__":
    create_skin_animation()
    
    # Save the blend file
    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", "track01_skin.blend"))
    
    # Export GLTF
    bpy.ops.export_scene.gltf(
        filepath=os.path.join(output_dir, "exports", "track01_skin.gltf"),
        export_animations=True,
        export_format='GLTF_SEPARATE'
    )
    
    # Export Alembic
    bpy.ops.wm.alembic_export(
        filepath=os.path.join(output_dir, "exports", "track01_skin.abc"),
        start=1,
        end=TOTAL_FRAMES,
        export_hair=False,
        export_particles=False
    )
    
    print("Track 01 - Skin: Export complete!")
