"""
SURYA Blender Utilities
Shared functions for all track animations
"""

import bpy
import math
from mathutils import Vector, Matrix, Euler
import random

# Color palette (RGB normalized 0-1)
COLORS = {
    "skin": (0.957, 0.447, 0.714, 1.0),       # #f472b6 Pink
    "u_saved_me": (0.133, 0.827, 0.933, 1.0), # #22d3ee Cyan
    "nothing": (0.4, 0.4, 0.4, 1.0),          # #666666 Grey
    "natures_call": (0.369, 0.918, 0.831, 1.0), # #5eead4 Teal
    "idk": (0.957, 0.447, 0.714, 1.0),        # #f472b6 Pink
    "with_u": (0.984, 0.749, 0.141, 1.0),     # #fbbf24 Gold
    "hollow": (0.984, 0.749, 0.141, 1.0),     # #fbbf24 Gold
    "intro": (0.102, 0.039, 0.180, 1.0),      # #1a0a2e Deep purple
    "white": (1.0, 1.0, 1.0, 1.0),
    "black": (0.0, 0.0, 0.0, 1.0),
}

# Animation settings
FPS = 30
DURATION_SECONDS = 25
TOTAL_FRAMES = FPS * DURATION_SECONDS  # 750 frames


def clear_scene():
    """Remove all objects from the current scene."""
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)
    
    # Clear orphan data
    for block in bpy.data.meshes:
        if block.users == 0:
            bpy.data.meshes.remove(block)
    for block in bpy.data.materials:
        if block.users == 0:
            bpy.data.materials.remove(block)
    for block in bpy.data.curves:
        if block.users == 0:
            bpy.data.curves.remove(block)


def create_scene(name):
    """Create a new scene with the given name."""
    scene = bpy.data.scenes.new(name)
    bpy.context.window.scene = scene
    scene.frame_start = 1
    scene.frame_end = TOTAL_FRAMES
    scene.render.fps = FPS
    return scene


def setup_scene(background_color=(0.1, 0.04, 0.18, 1.0)):
    """Setup scene with camera and world settings."""
    # Set world background
    world = bpy.context.scene.world
    if world is None:
        world = bpy.data.worlds.new("World")
        bpy.context.scene.world = world
    
    world.use_nodes = True
    bg_node = world.node_tree.nodes.get("Background")
    if bg_node:
        bg_node.inputs[0].default_value = background_color
        bg_node.inputs[1].default_value = 1.0  # Strength
    
    # Set render settings
    bpy.context.scene.render.resolution_x = 1920
    bpy.context.scene.render.resolution_y = 1080


def create_camera(location=(0, -10, 5), rotation=(1.1, 0, 0)):
    """Create and setup camera."""
    bpy.ops.object.camera_add(location=location)
    camera = bpy.context.active_object
    camera.rotation_euler = Euler(rotation, 'XYZ')
    bpy.context.scene.camera = camera
    return camera


def create_emission_material(name, color, strength=2.0):
    """Create an emission material for glowing objects."""
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    nodes = mat.node_tree.nodes
    links = mat.node_tree.links
    
    # Clear default nodes
    nodes.clear()
    
    # Create emission shader
    emission = nodes.new('ShaderNodeEmission')
    emission.inputs[0].default_value = color
    emission.inputs[1].default_value = strength
    
    # Output
    output = nodes.new('ShaderNodeOutputMaterial')
    links.new(emission.outputs[0], output.inputs[0])
    
    return mat


def create_basic_material(name, color, metallic=0.0, roughness=0.5):
    """Create a basic PBR material."""
    mat = bpy.data.materials.new(name=name)
    mat.use_nodes = True
    bsdf = mat.node_tree.nodes.get("Principled BSDF")
    if bsdf:
        bsdf.inputs["Base Color"].default_value = color
        bsdf.inputs["Metallic"].default_value = metallic
        bsdf.inputs["Roughness"].default_value = roughness
    return mat


def create_sphere(location=(0, 0, 0), radius=1.0, segments=32, rings=16, name="Sphere"):
    """Create a UV sphere."""
    bpy.ops.mesh.primitive_uv_sphere_add(
        radius=radius,
        segments=segments,
        ring_count=rings,
        location=location
    )
    obj = bpy.context.active_object
    obj.name = name
    return obj


def create_icosahedron(location=(0, 0, 0), radius=1.0, name="Icosahedron"):
    """Create an icosahedron."""
    bpy.ops.mesh.primitive_ico_sphere_add(
        radius=radius,
        subdivisions=1,
        location=location
    )
    obj = bpy.context.active_object
    obj.name = name
    return obj


def create_curve_from_points(points, name="Curve", bevel_depth=0.02):
    """Create a curve from a list of 3D points."""
    curve_data = bpy.data.curves.new(name=name, type='CURVE')
    curve_data.dimensions = '3D'
    curve_data.bevel_depth = bevel_depth
    curve_data.bevel_resolution = 4
    
    spline = curve_data.splines.new('NURBS')
    spline.points.add(len(points) - 1)
    
    for i, point in enumerate(points):
        spline.points[i].co = (point[0], point[1], point[2], 1)
    
    spline.use_endpoint_u = True
    
    curve_obj = bpy.data.objects.new(name, curve_data)
    bpy.context.collection.objects.link(curve_obj)
    
    return curve_obj


def keyframe_location(obj, frame, location):
    """Set a location keyframe."""
    obj.location = location
    obj.keyframe_insert(data_path="location", frame=frame)


def keyframe_scale(obj, frame, scale):
    """Set a scale keyframe."""
    if isinstance(scale, (int, float)):
        scale = (scale, scale, scale)
    obj.scale = scale
    obj.keyframe_insert(data_path="scale", frame=frame)


def keyframe_rotation(obj, frame, rotation):
    """Set a rotation keyframe (Euler)."""
    obj.rotation_euler = rotation
    obj.keyframe_insert(data_path="rotation_euler", frame=frame)


def animate_camera_orbit(camera, center=(0, 0, 0), radius=10, height=5, 
                         start_frame=1, end_frame=750, revolutions=1):
    """Animate camera orbiting around a center point."""
    for frame in range(start_frame, end_frame + 1):
        t = (frame - start_frame) / (end_frame - start_frame)
        angle = t * 2 * math.pi * revolutions
        
        x = center[0] + radius * math.cos(angle)
        y = center[1] + radius * math.sin(angle)
        z = center[2] + height
        
        camera.location = (x, y, z)
        camera.keyframe_insert(data_path="location", frame=frame)
        
        # Point at center
        direction = Vector(center) - Vector((x, y, z))
        rot_quat = direction.to_track_quat('-Z', 'Y')
        camera.rotation_euler = rot_quat.to_euler()
        camera.keyframe_insert(data_path="rotation_euler", frame=frame)


def create_star_field(count=200, radius=20, min_size=0.02, max_size=0.08):
    """Create a field of star particles."""
    stars = []
    for i in range(count):
        x = random.uniform(-radius, radius)
        y = random.uniform(-radius, radius)
        z = random.uniform(-radius/2, radius)
        size = random.uniform(min_size, max_size)
        
        bpy.ops.mesh.primitive_ico_sphere_add(radius=size, subdivisions=1, location=(x, y, z))
        star = bpy.context.active_object
        star.name = f"Star_{i:03d}"
        
        # Add emission material
        mat = create_emission_material(f"StarMat_{i:03d}", COLORS["white"], strength=5.0)
        star.data.materials.append(mat)
        stars.append(star)
    
    return stars


def smooth_interpolation(t):
    """Smooth step interpolation (ease in-out)."""
    return t * t * (3 - 2 * t)


def ease_in_out(t):
    """Ease in-out cubic."""
    if t < 0.5:
        return 4 * t * t * t
    else:
        return 1 - pow(-2 * t + 2, 3) / 2
