"""Physics Domain Tools for Godot MCP.

This module provides MCP tools for physics-related operations in Godot projects,
including setting rigid body properties and applying forces.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "physics_set_body_properties",
]


@mcp.tool()
def physics_set_body_properties(
    project_path: str,
    scene_path: str,
    node_path: str,
    mass: float | None = None,
    friction: float | None = None,
    bounce: float | None = None,
    gravity_scale: float | None = None,
    linear_damp: float | None = None,
    angular_damp: float | None = None,
) -> str:
    """Set physics properties for a RigidBody2D/3D node.

    Category: Physics

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        node_path: Path to the RigidBody node
        mass: Mass of the body in kg (default: 1.0)
        friction: Friction coefficient 0-1 (default: 1.0)
        bounce: Bounce/restitution coefficient 0-1 (default: 0.0)
        gravity_scale: Gravity scale multiplier (default: 1.0)
        linear_damp: Linear damping (default: 0.0)
        angular_damp: Angular damping (default: 0.0)

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

    if all(param is None for param in [mass, friction, bounce, gravity_scale, linear_damp, angular_damp]):
        return create_error_response("At least one property parameter must be specified")

    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,
            "nodePath": node_path,
        }

        if mass is not None:
            params["mass"] = mass
        if friction is not None:
            params["friction"] = friction
        if bounce is not None:
            params["bounce"] = bounce
        if gravity_scale is not None:
            params["gravityScale"] = gravity_scale
        if linear_damp is not None:
            params["linearDamp"] = linear_damp
        if angular_damp is not None:
            params["angularDamp"] = angular_damp

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

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(
                f"Failed to set body properties: {stderr}",
                ["Check if the node exists and is a RigidBody2D/3D"],
            )

        properties_set = []
        if mass is not None:
            properties_set.append(f"mass={mass}")
        if friction is not None:
            properties_set.append(f"friction={friction}")
        if bounce is not None:
            properties_set.append(f"bounce={bounce}")

        return f"Physics properties set for '{node_path}': {', '.join(properties_set)}."

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