"""Core animation playback engine."""

import time

from animate.animations.base import BaseAnimation
from animate.utils import clear_screen


def play(
    animation: BaseAnimation,
    loop: bool = False,
    repeat_count: int | None = None,
    timeout: float | None = None,
    fps: float | None = None,
    clear: bool = True,
) -> None:
    """Play an animation.

    Args:
        animation: The animation to play.
        loop: If True, play forever. Defaults to False.
        repeat_count: Number of times to repeat the animation. Ignored if loop=True.
            Defaults to 1 (play once).
        timeout: Maximum duration in seconds to play. Defaults to None (no limit).
        fps: Override animation's FPS. Defaults to None (use animation's FPS).
        clear: Whether to clear screen before playing. Defaults to True.

    Raises:
        ValueError: If both loop and repeat_count are specified, or if they're invalid.
    """
    if loop and repeat_count is not None:
        raise ValueError("Cannot specify both loop=True and repeat_count")

    frames = animation.get_frames()
    if not frames:
        raise ValueError("Animation has no frames")

    frame_rate = fps if fps is not None else animation.get_fps()
    if frame_rate <= 0:
        raise ValueError("FPS must be positive")

    frame_duration = 1.0 / frame_rate
    repetitions = repeat_count or 1

    start_time = time.time()
    frame_index = 0
    repeat_index = 0

    try:
        while True:
            # Check timeout
            if timeout is not None:
                elapsed = time.time() - start_time
                if elapsed >= timeout:
                    break

            # Check if we've finished all repetitions
            if not loop and repeat_index >= repetitions:
                break

            # Display current frame
            frame = frames[frame_index % len(frames)]
            # Clear screen before each frame for smooth animation
            if clear:
                clear_screen()
            print(frame, flush=True)

            # Move to next frame
            frame_index += 1

            # Check if we've completed a full cycle
            if frame_index % len(frames) == 0:
                if not loop:
                    repeat_index += 1

            # Sleep to maintain FPS
            time.sleep(frame_duration)

    except KeyboardInterrupt:
        pass
    finally:
        print()  # New line after animation ends
