"""Navigation Domain Tools for Godot MCP.

This module provides MCP tools for navigation-related operations in Godot projects,
including navigation regions, navigation meshes, and navigation agents.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "navigation_add_region",
    "navigation_set_navmesh",
    "navigation_add_obstacle",
    "navigation_add_agent",
]


@mcp.tool()
def navigation_add_region(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    region_name: str,
    region_type: str = "NavigationRegion2D",
) -> str:
    """Add a navigation region to a scene.

    Category: Navigation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        parent_node_path: Path to the parent node
        region_name: Name for the new navigation region node
        region_type: Type of navigation region (NavigationRegion2D, NavigationRegion3D, default: NavigationRegion2D)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path, region_name]):
        return create_error_response("All parameters except region_type are required")

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

    valid_types = ["NavigationRegion2D", "NavigationRegion3D"]
    if region_type not in valid_types:
        return create_error_response(
            f"Invalid region type: {region_type}",
            [f"Valid types are: {', '.join(valid_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}")

        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}")

        params = {
            "scenePath": scene_path,
            "parentNodePath": parent_node_path,
            "regionName": region_name,
            "regionType": region_type,
        }

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

        # Check for success message in stdout
        if stdout and "added successfully" in stdout:
            return f"Navigation region '{region_name}' of type '{region_type}' added successfully to '{parent_node_path}'."

        if stderr and "[ERROR]" in stderr:
            return create_error_response(
                f"Failed to add navigation region: {stderr}",
                ["Check if the parent node exists and the region type is valid"],
            )

        return f"Navigation region '{region_name}' of type '{region_type}' added successfully to '{parent_node_path}'."
    except Exception as error:
        return create_error_response(
            f"Failed to add navigation region: {error}",
            ["Ensure Godot is installed correctly"],
        )


@mcp.tool()
def navigation_set_navmesh(
    project_path: str,
    scene_path: str,
    region_path: str,
    navmesh_path: str | None = None,
    bake: bool = False,
) -> str:
    """Set or bake a navigation mesh for a navigation region.

    Category: Navigation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        region_path: Path to the navigation region node
        navmesh_path: Path to a saved NavigationMesh resource (optional)
        bake: Whether to bake a new navigation mesh (default: False)

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

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

    if navmesh_path and not validate_path(navmesh_path):
        return create_error_response("Invalid navmesh_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}")

        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}")

        params = {
            "scenePath": scene_path,
            "regionPath": region_path,
            "bake": bake,
        }

        if navmesh_path:
            params["navmeshPath"] = navmesh_path

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

        # Check for success message in stdout
        if stdout and "set successfully" in stdout:
            return f"Navigation mesh set successfully for region '{region_path}'."

        if stderr and "[ERROR]" in stderr:
            return create_error_response(
                f"Failed to set navigation mesh: {stderr}",
                ["Check if the navigation region exists"],
            )

        return f"Navigation mesh set successfully for region '{region_path}'."
    except Exception as error:
        return create_error_response(
            f"Failed to set navigation mesh: {error}",
            ["Ensure Godot is installed correctly"],
        )


@mcp.tool()
def navigation_add_obstacle(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    obstacle_name: str,
    obstacle_type: str = "NavigationObstacle2D",
    radius: float = 10.0,
) -> str:
    """Add a navigation obstacle to a scene.

    Category: Navigation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        parent_node_path: Path to the parent node
        obstacle_name: Name for the new obstacle node
        obstacle_type: Type of obstacle (NavigationObstacle2D, NavigationObstacle3D, default: NavigationObstacle2D)
        radius: Obstacle radius (default: 10.0)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path, obstacle_name]):
        return create_error_response("All parameters except obstacle_type and radius are required")

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

    valid_types = ["NavigationObstacle2D", "NavigationObstacle3D"]
    if obstacle_type not in valid_types:
        return create_error_response(
            f"Invalid obstacle type: {obstacle_type}",
            [f"Valid types are: {', '.join(valid_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}")

        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}")

        params = {
            "scenePath": scene_path,
            "parentNodePath": parent_node_path,
            "obstacleName": obstacle_name,
            "obstacleType": obstacle_type,
            "radius": radius,
        }

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

        # Check for success message in stdout
        if stdout and "added successfully" in stdout:
            return f"Navigation obstacle '{obstacle_name}' added successfully."

        if stderr and "[ERROR]" in stderr:
            return create_error_response(
                f"Failed to add navigation obstacle: {stderr}",
                ["Check if the parent node exists"],
            )

        return f"Navigation obstacle '{obstacle_name}' added successfully."
    except Exception as error:
        return create_error_response(
            f"Failed to add navigation obstacle: {error}",
            ["Ensure Godot is installed correctly"],
        )


@mcp.tool()
def navigation_add_agent(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    agent_name: str,
    agent_type: str = "NavigationAgent2D",
    max_speed: float = 200.0,
    radius: float = 10.0,
) -> str:
    """Add a navigation agent to a scene.

    Category: Navigation

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        parent_node_path: Path to the parent node
        agent_name: Name for the new agent node
        agent_type: Type of agent (NavigationAgent2D, NavigationAgent3D, default: NavigationAgent2D)
        max_speed: Maximum movement speed (default: 200.0)
        radius: Agent radius for avoidance (default: 10.0)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path, agent_name]):
        return create_error_response("All parameters except agent_type, max_speed, and radius are required")

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

    valid_types = ["NavigationAgent2D", "NavigationAgent3D"]
    if agent_type not in valid_types:
        return create_error_response(
            f"Invalid agent type: {agent_type}",
            [f"Valid types are: {', '.join(valid_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}")

        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}")

        params = {
            "scenePath": scene_path,
            "parentNodePath": parent_node_path,
            "agentName": agent_name,
            "agentType": agent_type,
            "maxSpeed": max_speed,
            "radius": radius,
        }

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

        # Check for success message in stdout
        if stdout and "added successfully" in stdout:
            return f"Navigation agent '{agent_name}' added successfully."

        if stderr and "[ERROR]" in stderr:
            return create_error_response(
                f"Failed to add navigation agent: {stderr}",
                ["Check if the parent node exists"],
            )

        return f"Navigation agent '{agent_name}' added successfully."
    except Exception as error:
        return create_error_response(
            f"Failed to add navigation agent: {error}",
            ["Ensure Godot is installed correctly"],
        )
