"""Animation Domain Tools for Godot MCP.

This module provides MCP tools for animation-related operations in Godot projects,
including creating animations, managing tracks, setting keyframes, and querying animation data.
"""

import asyncio
from pathlib import Path

from godot_mcp.core import (
    create_error_response,
    extract_json_from_output,
    godot_server,
    mcp,
    validate_path,
)

__all__ = [
    "animation_create",
    "animation_add_track",
    "animation_set_keyframe",
    "animation_get_info",
    "animation_list",
]


@mcp.tool()
def animation_create(
    project_path: str,
    scene_path: str,
    animation_name: str,
    duration: float = 1.0,
    loop: bool = False,
) -> str:
    """Create an Animation resource and add it to a scene.

    Category: Animation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        animation_name: Name of the animation to create
        duration: Duration of the animation in seconds (default: 1.0)
        loop: Whether the animation should loop (default: False)

    Returns:
        Success message or error description
    """
    if not project_path or not scene_path or not animation_name:
        return create_error_response("Missing required parameters: project_path, scene_path, and animation_name are required")

    if not validate_path(project_path) or not validate_path(scene_path):
        return create_error_response("Invalid path")

    try:
        project_file = Path(project_path) / "project.godot"
        if not project_file.exists():
            return create_error_response(
                f"Not a valid Godot project: {project_path}",
                ["Ensure the path points to a directory containing a project.godot file"],
            )

        scene_full_path = Path(project_path) / scene_path
        if not scene_full_path.exists():
            return create_error_response(
                f"Scene file does not exist: {scene_path}",
                ["Ensure the scene path is correct"],
            )

        params = {
            "scenePath": scene_path,
            "animationName": animation_name,
            "duration": duration,
            "loop": loop,
        }

        stdout, stderr = asyncio.run(
            godot_server.execute_operation("create_animation", params, project_path)
        )

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(
                f"Failed to create animation: {stderr}",
                ["Check if the animation parameters are valid"],
            )

        return f"Animation '{animation_name}' created successfully in scene '{scene_path}' with duration {duration}s."

    except Exception as error:
        return create_error_response(
            f"Failed to create animation: {error}",
            ["Ensure Godot is installed correctly", "Check the project and scene paths"],
        )


@mcp.tool()
def animation_add_track(
    project_path: str,
    scene_path: str,
    animation_name: str,
    track_type: str,
    track_path: str,
) -> str:
    """Add a track to an existing animation.

    Category: Animation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        animation_name: Name of the animation
        track_type: Type of track (value, method, bezier, audio, animation)
        track_path: Node path for the track (e.g., "Player:position")

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, animation_name, track_type, track_path]):
        return create_error_response("All parameters are required")

    if not validate_path(project_path) or not validate_path(scene_path):
        return create_error_response("Invalid path")

    valid_track_types = ["value", "method", "bezier", "audio", "animation"]
    if track_type not in valid_track_types:
        return create_error_response(
            f"Invalid track type: {track_type}",
            [f"Valid types are: {', '.join(valid_track_types)}"],
        )

    try:
        project_file = Path(project_path) / "project.godot"
        if not project_file.exists():
            return create_error_response(f"Not a valid Godot project: {project_path}")

        params = {
            "scenePath": scene_path,
            "animationName": animation_name,
            "trackType": track_type,
            "trackPath": track_path,
        }

        stdout, stderr = asyncio.run(
            godot_server.execute_operation("add_animation_track", params, project_path)
        )

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to add track: {stderr}")

        return f"Track '{track_path}' ({track_type}) added to animation '{animation_name}'."

    except Exception as error:
        return create_error_response(f"Failed to add animation track: {error}")


@mcp.tool()
def animation_set_keyframe(
    project_path: str,
    scene_path: str,
    animation_name: str,
    track_index: int,
    time: float,
    value: str,
) -> str:
    """Set a keyframe in an animation track.

    Category: Animation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        animation_name: Name of the animation
        track_index: Index of the track (0-based)
        time: Time position for the keyframe in seconds
        value: Value for the keyframe (JSON string for complex values)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, animation_name]):
        return create_error_response("project_path, scene_path, and animation_name are required")

    if not validate_path(project_path) or not validate_path(scene_path):
        return create_error_response("Invalid path")

    try:
        project_file = Path(project_path) / "project.godot"
        if not project_file.exists():
            return create_error_response(f"Not a valid Godot project: {project_path}")

        params = {
            "scenePath": scene_path,
            "animationName": animation_name,
            "trackIndex": track_index,
            "time": time,
            "value": value,
        }

        stdout, stderr = asyncio.run(
            godot_server.execute_operation("set_animation_keyframe", params, project_path)
        )

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to set keyframe: {stderr}")

        return f"Keyframe set at time {time}s in track {track_index} of animation '{animation_name}'."

    except Exception as error:
        return create_error_response(f"Failed to set keyframe: {error}")


@mcp.tool()
def animation_get_info(
    project_path: str,
    scene_path: str,
    animation_name: str,
) -> str:
    """Get information about an animation.

    Category: Animation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        animation_name: Name of the animation

    Returns:
        JSON string containing animation information or error description
    """
    if not all([project_path, scene_path, animation_name]):
        return create_error_response("All parameters are required")

    if not validate_path(project_path) or not validate_path(scene_path):
        return create_error_response("Invalid path")

    try:
        project_file = Path(project_path) / "project.godot"
        if not project_file.exists():
            return create_error_response(f"Not a valid Godot project: {project_path}")

        params = {
            "scenePath": scene_path,
            "animationName": animation_name,
        }

        stdout, stderr = asyncio.run(
            godot_server.execute_operation("get_animation_info", params, project_path)
        )

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to get animation info: {stderr}")

        json_output = extract_json_from_output(stdout)
        if json_output:
            return json_output

        return stdout

    except Exception as error:
        return create_error_response(f"Failed to get animation info: {error}")


@mcp.tool()
def animation_list(
    project_path: str,
    scene_path: str,
) -> str:
    """List all animations in a scene.

    Category: Animation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)

    Returns:
        JSON string containing list of animations or error description
    """
    if not project_path or not scene_path:
        return create_error_response("project_path and scene_path are required")

    if not validate_path(project_path) or not validate_path(scene_path):
        return create_error_response("Invalid path")

    try:
        project_file = Path(project_path) / "project.godot"
        if not project_file.exists():
            return create_error_response(f"Not a valid Godot project: {project_path}")

        params = {
            "scenePath": scene_path,
        }

        stdout, stderr = asyncio.run(
            godot_server.execute_operation("list_animations", params, project_path)
        )

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to list animations: {stderr}")

        json_output = extract_json_from_output(stdout)
        if json_output:
            return json_output

        return stdout

    except Exception as error:
        return create_error_response(f"Failed to list animations: {error}")
