"""Collision Domain Tools for Godot MCP.

This module provides MCP tools for collision shape operations in Godot projects,
including adding collision shapes, setting properties, and configuring collision layers.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "collision_add_shape",
    "collision_set_shape_properties",
    "collision_set_layers",
]


@mcp.tool()
def collision_add_shape(
    project_path: str,
    scene_path: str,
    node_path: str,
    shape_type: str,
    shape_properties: str | None = None,
) -> str:
    """Add a collision shape to a CollisionObject2D/3D node.

    Category: Collision

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        node_path: Path to the CollisionObject node (e.g., "Player", "Enemy/CollisionObject2D")
        shape_type: Type of collision shape (RectangleShape2D, CircleShape2D, BoxShape3D, SphereShape3D, CapsuleShape2D, etc.)
        shape_properties: JSON string of shape properties (e.g., '{"size": [10, 20]}' for rectangle)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, node_path, shape_type]):
        return create_error_response("All parameters except shape_properties 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,
            "nodePath": node_path,
            "shapeType": shape_type,
        }
        if shape_properties:
            params["shapeProperties"] = shape_properties

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

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(
                f"Failed to add collision shape: {stderr}",
                ["Check if the node exists and is a CollisionObject2D/3D", "Verify the shape type is valid"],
            )

        return f"Collision shape '{shape_type}' added to node '{node_path}' in scene '{scene_path}'."

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


@mcp.tool()
def collision_set_shape_properties(
    project_path: str,
    scene_path: str,
    node_path: str,
    shape_index: int,
    properties: str,
) -> str:
    """Set properties of a collision shape.

    Category: Collision

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        node_path: Path to the CollisionShape node
        shape_index: Index of the shape (0 for first CollisionShape child)
        properties: JSON string of properties to set (e.g., '{"size": [20, 30], "position": [5, 0]}')

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, node_path, properties]):
        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,
            "nodePath": node_path,
            "shapeIndex": shape_index,
            "properties": properties,
        }

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

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

        return f"Collision shape properties updated for '{node_path}' shape {shape_index}."

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


@mcp.tool()
def collision_set_layers(
    project_path: str,
    scene_path: str,
    node_path: str,
    collision_layer: int | None = None,
    collision_mask: int | None = None,
) -> str:
    """Configure collision layers and masks for a CollisionObject node.

    Category: Collision

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        node_path: Path to the CollisionObject node
        collision_layer: Collision layer bitmask (which layers this object is on)
        collision_mask: Collision mask bitmask (which layers this object can collide with)

    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 collision_layer is None and collision_mask is None:
        return create_error_response("At least one of collision_layer or collision_mask 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}")

        params = {
            "scenePath": scene_path,
            "nodePath": node_path,
        }
        if collision_layer is not None:
            params["collisionLayer"] = collision_layer
        if collision_mask is not None:
            params["collisionMask"] = collision_mask

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

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

        return f"Collision layers configured for node '{node_path}'."

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