"""Resource Domain Tools for Godot MCP.

This module contains all resource-related MCP tools for managing Godot resources,
including listing resources, getting UIDs, creating materials, and exporting mesh libraries.
"""

import asyncio

from pathlib import Path

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

__all__ = [
    "resource_list",
    "resource_get_uid",
    "resource_create_material",
    "resource_get_material_properties",
    "resource_export_mesh_library",
]


@mcp.tool()
def resource_list(
    project_path: str,
    directory: str = "",
    extensions: list[str] = None,
    recursive: bool = True,
) -> str:
    """List resource files in a Godot project.

    Category: Resource

    Args:
        project_path: Path to the Godot project directory
        directory: Optional subdirectory to search in (relative to project root)
        extensions: List of file extensions to include (default: common asset types)
        recursive: Whether to search recursively (default: True)

    Returns:
        JSON containing categorized resource files
    """
    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:
        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"],
            )

        # Default extensions if none provided
        if extensions is None:
            extensions = [
                # Images
                "png",
                "jpg",
                "jpeg",
                "webp",
                "svg",
                "bmp",
                # Audio
                "wav",
                "mp3",
                "ogg",
                # 3D models
                "glb",
                "gltf",
                "obj",
                "fbx",
                # Fonts
                "ttf",
                "otf",
                # Resources
                "tres",
                "res",
            ]

        params = {
            "directory": directory,
            "extensions": extensions,
            "recursive": recursive,
        }

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

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

        return extract_json_from_output(stdout)
    except Exception as error:
        return create_error_response(
            f"Failed to list resources: {error}",
            ["Ensure Godot is installed correctly"],
        )


@mcp.tool()
def resource_get_uid(project_path: str, file_path: str) -> str:
    """Get the UID for a specific file in a Godot project (for Godot 4.4+).

    Category: Resource

    Args:
        project_path: Path to the Godot project directory
        file_path: Path to the file (relative to project) for which to get the UID
    """
    if not project_path or not file_path:
        return create_error_response("Project path and file path are required")

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

    try:
        # Prepare parameters for the operation
        params = {"filePath": file_path}

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

        if stderr:
            return create_error_response(
                f"Failed to get UID: {stderr}",
                ["Ensure the file exists in the project"],
            )

        # The UID operation returns JSON output
        return stdout
    except Exception as error:
        return create_error_response(
            f"Failed to get UID: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def resource_create_material(
    project_path: str,
    save_path: str,
    albedo_color: str = None,
    roughness: float = None,
    metallic: float = None,
    emission_enabled: bool = False,
    emission_color: str = None,
    emission_energy: float = None,
    transparency: str = None,
    cull_mode: str = None,
    scene_path: str = None,
    target_node_path: str = None,
) -> str:
    """Create a StandardMaterial3D resource and optionally assign it to a node.

    Category: Resource

    Args:
        project_path: Path to the Godot project directory
        save_path: Path where the material will be saved (e.g., "materials/red.tres")
        albedo_color: Base color as hex string (e.g., "#FF0000") or color name (e.g., "red")
        roughness: Surface roughness (0.0 = smooth/reflective, 1.0 = rough)
        metallic: Metallic value (0.0 = non-metal, 1.0 = metal)
        emission_enabled: Enable emission/glow effect
        emission_color: Emission color as hex string or color name
        emission_energy: Emission intensity multiplier
        transparency: Transparency mode ("disabled", "alpha", "alpha_scissor", "alpha_hash")
        cull_mode: Face culling mode ("back", "front", "disabled")
        scene_path: Optional scene path to assign the material to a node
        target_node_path: Optional node path to assign the material (e.g., "root/MeshInstance3D")
    """
    if not project_path or not save_path:
        return create_error_response("Project path and save path are required")

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

        # If assigning to a node, check if the scene exists
        if scene_path and target_node_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}",
                    [
                        "Ensure the scene path is correct",
                        "Use scene_create to create a new scene first",
                    ],
                )

        # Prepare parameters for the operation
        params = {
            "savePath": save_path,
        }

        # Add optional material properties
        if albedo_color is not None:
            params["albedoColor"] = albedo_color
        if roughness is not None:
            params["roughness"] = roughness
        if metallic is not None:
            params["metallic"] = metallic
        if emission_enabled:
            params["emissionEnabled"] = emission_enabled
        if emission_color is not None:
            params["emissionColor"] = emission_color
        if emission_energy is not None:
            params["emissionEnergy"] = emission_energy
        if transparency is not None:
            params["transparency"] = transparency
        if cull_mode is not None:
            params["cullMode"] = cull_mode

        # Add node assignment parameters
        if scene_path and target_node_path:
            params["scenePath"] = scene_path
            params["targetNodePath"] = target_node_path

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

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

        if scene_path and target_node_path:
            return f"Material created at '{save_path}' and assigned to node '{target_node_path}'"
        return f"Material created successfully at: {save_path}"
    except Exception as error:
        return create_error_response(
            f"Failed to create material: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def resource_get_material_properties(
    project_path: str,
    material_path: str,
) -> str:
    """Get properties from a material resource file.

    Category: Resource

    Args:
        project_path: Path to the Godot project directory
        material_path: Path to the material file (e.g., "materials/red.tres")

    Returns:
        JSON containing material properties: type, albedo_color, metallic, roughness, etc.
    """
    if not project_path or not material_path:
        return create_error_response("Project path and material path are required")

    if not validate_path(project_path) or not validate_path(material_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 material file exists
        material_full_path = Path(project_path) / material_path
        if not material_full_path.exists():
            return create_error_response(
                f"Material file does not exist: {material_path}",
                [
                    "Ensure the material path is correct",
                    "Use resource_create_material to create a new material first",
                ],
            )

        # Prepare parameters for the operation
        params = {
            "materialPath": material_path,
        }

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

        if stderr and "Failed to" in stderr:
            return create_error_response(
                f"Failed to get material properties: {stderr}",
                [
                    "Check if the material 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 material properties: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )


@mcp.tool()
def resource_export_mesh_library(
    project_path: str,
    scene_path: str,
    output_path: str,
    mesh_item_names: list[str] = None,
) -> str:
    """Export a scene as a MeshLibrary resource.

    Category: Resource

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (.tscn) to export
        output_path: Path where the mesh library (.res) will be saved
        mesh_item_names: Optional names of specific mesh items to include (defaults to all)
    """
    if not project_path or not scene_path or not output_path:
        return create_error_response("Missing required parameters")

    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,
            "outputPath": output_path,
        }

        if mesh_item_names:
            params["meshItemNames"] = mesh_item_names

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

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

        return f"MeshLibrary exported successfully to: {output_path}"
    except Exception as error:
        return create_error_response(
            f"Failed to export mesh library: {error}",
            [
                "Ensure Godot is installed correctly",
                "Verify the project path is accessible",
            ],
        )
