#!/usr/bin/env python3
"""
Move Animation - Move objects along paths with various motion types.

Provides flexible movement primitives for objects along linear, arc, or custom paths.
"""

import sys
from pathlib import Path
import math

sys.path.append(str(Path(__file__).parent.parent))

from core.gif_builder import GIFBuilder
from core.frame_composer import create_blank_frame, draw_circle, draw_emoji_enhanced
from core.easing import interpolate, calculate_arc_motion


def create_move_animation(
    object_type: str = 'emoji',
    object_data: dict | None = None,
    start_pos: tuple[int, int] = (50, 240),
    end_pos: tuple[int, int] = (430, 240),
    num_frames: int = 30,
    motion_type: str = 'linear',  # 'linear', 'arc', 'bezier', 'circle', 'wave'
    easing: str = 'ease_out',
    motion_params: dict | None = None,
    frame_width: int = 480,
    frame_height: int = 480,
    bg_color: tuple[int, int, int] = (255, 255, 255)
) -> list:
    """
    Create frames showing object moving along a path.

    Args:
        object_type: 'circle', 'emoji', or 'custom'
        object_data: Data for the object
        start_pos: Starting (x, y) position
        end_pos: Ending (x, y) position
        num_frames: Number of frames
        motion_type: Type of motion path
        easing: Easing function name
        motion_params: Additional parameters for motion (e.g., {'arc_height': 100})
        frame_width: Frame width
        frame_height: Frame height
        bg_color: Background color

    Returns:
        List of frames
    """
    frames = []

    # Default object data
    if object_data is None:
        if object_type == 'circle':
            object_data = {'radius': 30, 'color': (100, 150, 255)}
        elif object_type == 'emoji':
            object_data = {'emoji': '🚀', 'size': 60}

    # Default motion params
    if motion_params is None:
        motion_params = {}

    for i in range(num_frames):
        frame = create_blank_frame(frame_width, frame_height, bg_color)

        t = i / (num_frames - 1) if num_frames > 1 else 0

        # Calculate position based on motion type
        if motion_type == 'linear':
            # Straight line with easing
            x = interpolate(start_pos[0], end_pos[0], t, easing)
            y = interpolate(start_pos[1], end_pos[1], t, easing)

        elif motion_type == 'arc':
            # Parabolic arc
            arc_height = motion_params.get('arc_height', 100)
            x, y = calculate_arc_motion(start_pos, end_pos, arc_height, t)

        elif motion_type == 'circle':
            # Circular motion around a center
            center = motion_params.get('center', (frame_width // 2, frame_height // 2))
            radius = motion_params.get('radius', 150)
            start_angle = motion_params.get('start_angle', 0)
            angle_range = motion_params.get('angle_range', 360)  # Full circle

            angle = start_angle + (angle_range * t)
            angle_rad = math.radians(angle)

            x = center[0] + radius * math.cos(angle_rad)
            y = center[1] + radius * math.sin(angle_rad)

        elif motion_type == 'wave':
            # Move in straight line but add wave motion
            wave_amplitude = motion_params.get('wave_amplitude', 50)
            wave_frequency = motion_params.get('wave_frequency', 2)

            # Base linear motion
            base_x = interpolate(start_pos[0], end_pos[0], t, easing)
            base_y = interpolate(start_pos[1], end_pos[1], t, easing)

            # Add wave offset perpendicular to motion direction
            dx = end_pos[0] - start_pos[0]
            dy = end_pos[1] - start_pos[1]
            length = math.sqrt(dx * dx + dy * dy)

            if length > 0:
                # Perpendicular direction
                perp_x = -dy / length
                perp_y = dx / length

                # Wave offset
                wave_offset = math.sin(t * wave_frequency * 2 * math.pi) * wave_amplitude

                x = base_x + perp_x * wave_offset
                y = base_y + perp_y * wave_offset
            else:
                x, y = base_x, base_y

        elif motion_type == 'bezier':
            # Quadratic bezier curve
            control_point = motion_params.get('control_point', (
                (start_pos[0] + end_pos[0]) // 2,
                (start_pos[1] + end_pos[1]) // 2 - 100
            ))

            # Quadratic Bezier formula: B(t) = (1-t)²P0 + 2(1-t)tP1 + t²P2
            x = (1 - t) ** 2 * start_pos[0] + 2 * (1 - t) * t * control_point[0] + t ** 2 * end_pos[0]
            y = (1 - t) ** 2 * start_pos[1] + 2 * (1 - t) * t * control_point[1] + t ** 2 * end_pos[1]

        else:
            # Default to linear
            x = interpolate(start_pos[0], end_pos[0], t, easing)
            y = interpolate(start_pos[1], end_pos[1], t, easing)

        # Draw object at calculated position
        x, y = int(x), int(y)

        if object_type == 'circle':
            draw_circle(
                frame,
                center=(x, y),
                radius=object_data['radius'],
                fill_color=object_data['color']
            )
        elif object_type == 'emoji':
            draw_emoji_enhanced(
                frame,
                emoji=object_data['emoji'],
                position=(x - object_data['size'] // 2, y - object_data['size'] // 2),
                size=object_data['size'],
                shadow=object_data.get('shadow', True)
            )

        frames.append(frame)

    return frames


def create_path_from_points(points: list[tuple[int, int]],
                            num_frames: int = 60,
                            easing: str = 'ease_in_out') -> list[tuple[int, int]]:
    """
    Create a smooth path through multiple points.

    Args:
        points: List of (x, y) waypoints
        num_frames: Total number of frames
        easing: Easing between points

    Returns:
        List of (x, y) positions for each frame
    """
    if len(points) < 2:
        return points * num_frames

    path = []
    frames_per_segment = num_frames // (len(points) - 1)

    for i in range(len(points) - 1):
        start = points[i]
        end = points[i + 1]

        # Last segment gets remaining frames
        if i == len(points) - 2:
            segment_frames = num_frames - len(path)
        else:
            segment_frames = frames_per_segment

        for j in range(segment_frames):
            t = j / segment_frames if segment_frames > 0 else 0
            x = interpolate(start[0], end[0], t, easing)
            y = interpolate(start[1], end[1], t, easing)
            path.append((int(x), int(y)))

    return path


def apply_trail_effect(frames: list, trail_length: int = 5,
                      fade_alpha: float = 0.3) -> list:
    """
    Add motion trail effect to moving object.

    Args:
        frames: List of frames with moving object
        trail_length: Number of previous frames to blend
        fade_alpha: Opacity of trail frames

    Returns:
        List of frames with trail effect
    """
    from PIL import Image, ImageChops
    import numpy as np

    trailed_frames = []

    for i, frame in enumerate(frames):
        # Start with current frame
        result = frame.copy()

        # Blend previous frames
        for j in range(1, min(trail_length + 1, i + 1)):
            prev_frame = frames[i - j]

            # Calculate fade
            alpha = fade_alpha ** j

            # Blend
            result_array = np.array(result, dtype=np.float32)
            prev_array = np.array(prev_frame, dtype=np.float32)

            blended = result_array * (1 - alpha) + prev_array * alpha
            result = Image.fromarray(blended.astype(np.uint8))

        trailed_frames.append(result)

    return trailed_frames


# Example usage
if __name__ == '__main__':
    print("Creating movement examples...")

    # Example 1: Linear movement
    builder = GIFBuilder(width=480, height=480, fps=20)
    frames = create_move_animation(
        object_type='emoji',
        object_data={'emoji': '🚀', 'size': 60},
        start_pos=(50, 240),
        end_pos=(430, 240),
        num_frames=30,
        motion_type='linear',
        easing='ease_out'
    )
    builder.add_frames(frames)
    builder.save('move_linear.gif', num_colors=128)

    # Example 2: Arc movement
    builder.clear()
    frames = create_move_animation(
        object_type='emoji',
        object_data={'emoji': '⚽', 'size': 60},
        start_pos=(50, 350),
        end_pos=(430, 350),
        num_frames=30,
        motion_type='arc',
        motion_params={'arc_height': 150},
        easing='linear'
    )
    builder.add_frames(frames)
    builder.save('move_arc.gif', num_colors=128)

    # Example 3: Circular movement
    builder.clear()
    frames = create_move_animation(
        object_type='emoji',
        object_data={'emoji': '🌍', 'size': 50},
        start_pos=(0, 0),  # Ignored for circle
        end_pos=(0, 0),    # Ignored for circle
        num_frames=40,
        motion_type='circle',
        motion_params={
            'center': (240, 240),
            'radius': 120,
            'start_angle': 0,
            'angle_range': 360
        },
        easing='linear'
    )
    builder.add_frames(frames)
    builder.save('move_circle.gif', num_colors=128)

    print("Created movement examples!")
