"""Scene Domain Tools for Godot MCP.

This module provides MCP tools for scene-related operations in Godot projects,
including creating, saving, listing, querying, and instantiating scenes.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "scene_create",
    "scene_save",
    "scene_list",
    "scene_get_tree",
    "scene_instantiate",
]


@mcp.tool()
def scene_create(project_path: str, scene_path: str, root_node_type: str = "Node2D") -> str:
    """Create a new Godot scene file.

    Category: Scene

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path where the scene file will be saved (relative to project)
        root_node_type: Type of the root node (e.g., Node2D, Node3D)
    """
    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:
        # Check if the project directory exists and contains a project.godot file
        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"],
            )

        # Prepare parameters for the operation
        params = {
            "scenePath": scene_path,
            "rootNodeType": root_node_type,
        }

        # Execute the operation
        stdout, stderr = asyncio.run(
            godot_server.execute_operation("create_scene", params, project_path)
        )

        if stderr and "Failed to" in stderr:
            return create_error_response(
                f"Failed to create scene: {stderr}",
                [
                    "Check if the root node type is valid",
                    "Ensure you have write permissions",
                ],
            )

        return f"Scene created successfully at: {scene_path}\n\nOutput: {stdout}"
    except Exception as error:
        return create_error_response(
            f"Failed to create scene: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def scene_save(project_path: str, scene_path: str, new_path: str = None) -> str:
    """Save changes to a scene file.

    Category: Scene

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        new_path: Optional new path to save the scene to (for creating variants)
    """
    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:
        # Prepare parameters for the operation
        params = {"scenePath": scene_path}

        if new_path:
            params["newPath"] = new_path

        # Execute the operation
        stdout, stderr = asyncio.run(
            godot_server.execute_operation("save_scene", params, project_path)
        )

        if stderr and "Failed to" in stderr:
            return create_error_response(
                f"Failed to save scene: {stderr}",
                ["Check if the scene file exists", "Ensure you have write permissions"],
            )

        save_target = new_path if new_path else scene_path
        return f"Scene saved successfully to: {save_target}"
    except Exception as error:
        return create_error_response(
            f"Failed to save scene: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def scene_list(
    project_path: str,
    directory: str = "",
    recursive: bool = True,
) -> str:
    """List all scene files (.tscn) in a Godot project.

    Category: Scene

    Args:
        project_path: Path to the Godot project directory
        directory: Optional subdirectory to search in (relative to project root)
        recursive: Whether to search recursively (default: True)

    Returns:
        JSON array containing scene file paths relative to project root
    """
    if not project_path:
        return create_error_response("Project path is required")

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

    try:
        # Check if the project directory exists and contains a project.godot file
        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"],
            )

        # Prepare parameters for the operation
        params = {
            "directory": directory,
            "recursive": recursive,
        }

        # Execute the operation
        stdout, stderr = asyncio.run(
            godot_server.execute_operation("list_scenes", params, project_path)
        )

        if stderr and "Failed to" in stderr:
            return create_error_response(
                f"Failed to list scenes: {stderr}",
                ["Ensure the directory exists"],
            )

        # Extract and return the JSON output from the GDScript
        return extract_json_from_output(stdout)
    except Exception as error:
        return create_error_response(
            f"Failed to list scenes: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def scene_get_tree(
    project_path: str,
    scene_path: str,
    max_depth: int = -1,
) -> str:
    """Get the node tree structure of a scene.

    Category: Scene

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        max_depth: Maximum depth to traverse (-1 for unlimited, default: -1)

    Returns:
        JSON containing the scene's node tree with node names, types, and children
    """
    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:
        # Check if the project directory exists and contains a project.godot file
        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"],
            )

        # Check if the scene file exists
        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",
                    "Use scene_list to see available scenes",
                ],
            )

        # Prepare parameters for the operation
        params = {
            "scenePath": scene_path,
            "maxDepth": max_depth,
        }

        # Execute the operation
        stdout, stderr = asyncio.run(
            godot_server.execute_operation("get_scene_tree", params, project_path)
        )

        if stderr and "Failed to" in stderr:
            return create_error_response(
                f"Failed to get scene tree: {stderr}",
                ["Check if the scene file is valid"],
            )

        # Extract and return the JSON output from the GDScript
        return extract_json_from_output(stdout)
    except Exception as error:
        return create_error_response(
            f"Failed to get scene tree: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def scene_instantiate(
    project_path: str,
    target_scene_path: str,
    source_scene_path: str,
    parent_node_path: str = "root",
    instance_name: str = None,
) -> str:
    """Instance a scene as a child node in another scene.

    Category: Scene

    Args:
        project_path: Path to the Godot project directory
        target_scene_path: Path to the scene where the instance will be added
        source_scene_path: Path to the scene to instance (e.g., "scenes/player.tscn")
        parent_node_path: Path to the parent node (default: "root")
        instance_name: Optional custom name for the instance

    Returns:
        Success message or error description
    """
    if not project_path or not target_scene_path or not source_scene_path:
        return create_error_response("Missing required parameters")

    if not validate_path(project_path) or not validate_path(target_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"],
            )

        target_full_path = Path(project_path) / target_scene_path
        if not target_full_path.exists():
            return create_error_response(
                f"Target scene does not exist: {target_scene_path}",
                ["Ensure the target scene path is correct"],
            )

        source_full_path = Path(project_path) / source_scene_path
        if not source_full_path.exists():
            return create_error_response(
                f"Source scene does not exist: {source_scene_path}",
                ["Ensure the source scene path is correct"],
            )

        params = {
            "targetScenePath": target_scene_path,
            "sourceScenePath": source_scene_path,
            "parentNodePath": parent_node_path,
        }

        if instance_name:
            params["instanceName"] = instance_name

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

        if stderr and ("Failed to" in stderr or "not found" in stderr.lower()):
            return create_error_response(
                f"Failed to instance scene: {stderr}",
                ["Check if the scene paths are correct"],
            )

        name = (
            instance_name
            if instance_name
            else source_scene_path.split("/")[-1].replace(".tscn", "")
        )
        return f"Scene '{source_scene_path}' instanced as '{name}' in '{target_scene_path}'."
    except Exception as error:
        return create_error_response(
            f"Failed to instance scene: {error}",
            ["Ensure Godot is installed correctly"],
        )
