"""Particle Domain Tools for Godot MCP.

This module provides MCP tools for particle system operations in Godot projects,
including creating particle emitters and configuring particle properties.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "particle_add_system",
    "particle_set_properties",
    "particle_start_emitting",
]


@mcp.tool()
def particle_add_system(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    particle_name: str,
    particle_type: str = "CPUParticles2D",
    amount: int = 8,
    emitting: bool = True,
) -> str:
    """Add a particle system to a scene.

    Category: Particle

    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
        particle_name: Name for the new particle system
        particle_type: Type of particle system (CPUParticles2D, CPUParticles3D, GPUParticles2D, GPUParticles3D, default: CPUParticles2D)
        amount: Number of particles (default: 8)
        emitting: Whether to start emitting immediately (default: True)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path, particle_name]):
        return create_error_response("All parameters except particle_type, amount, and emitting are required")

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

    valid_types = ["CPUParticles2D", "CPUParticles3D", "GPUParticles2D", "GPUParticles3D"]
    if particle_type not in valid_types:
        return create_error_response(
            f"Invalid particle type: {particle_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,
            "particleName": particle_name,
            "particleType": particle_type,
            "amount": amount,
            "emitting": emitting,
        }

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

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to add particle system: {stderr}")

        return f"Particle system '{particle_name}' ({particle_type}) added to '{parent_node_path}'."

    except Exception as error:
        return create_error_response(f"Failed to add particle system: {error}")


@mcp.tool()
def particle_set_properties(
    project_path: str,
    scene_path: str,
    particle_path: str,
    lifetime: float | None = None,
    speed_scale: float | None = None,
    explosiveness: float | None = None,
    randomness: float | None = None,
    direction: str | None = None,
    spread: float | None = None,
    gravity: str | None = None,
    initial_velocity_min: float | None = None,
    initial_velocity_max: float | None = None,
) -> str:
    """Set properties of a particle system.

    Category: Particle

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        particle_path: Path to the particle system node
        lifetime: Particle lifetime in seconds
        speed_scale: Speed scale multiplier
        explosiveness: Explosiveness ratio (0-1)
        randomness: Emission randomness (0-1)
        direction: Emission direction as JSON array [x, y] or [x, y, z]
        spread: Emission spread angle in degrees
        gravity: Gravity vector as JSON array [x, y] or [x, y, z]
        initial_velocity_min: Minimum initial velocity
        initial_velocity_max: Maximum initial velocity

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

    property_params = [lifetime, speed_scale, explosiveness, randomness, direction, spread,
                       gravity, initial_velocity_min, initial_velocity_max]
    if all(param is None for param in property_params):
        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}")

        params = {
            "scenePath": scene_path,
            "particlePath": particle_path,
        }

        if lifetime is not None:
            params["lifetime"] = lifetime
        if speed_scale is not None:
            params["speedScale"] = speed_scale
        if explosiveness is not None:
            params["explosiveness"] = explosiveness
        if randomness is not None:
            params["randomness"] = randomness
        if direction:
            params["direction"] = direction
        if spread is not None:
            params["spread"] = spread
        if gravity:
            params["gravity"] = gravity
        if initial_velocity_min is not None:
            params["initialVelocityMin"] = initial_velocity_min
        if initial_velocity_max is not None:
            params["initialVelocityMax"] = initial_velocity_max

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

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

        return f"Particle properties set for '{particle_path}'."

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


@mcp.tool()
def particle_start_emitting(
    project_path: str,
    scene_path: str,
    particle_path: str,
    emitting: bool = True,
) -> str:
    """Start or stop particle emission.

    Category: Particle

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        particle_path: Path to the particle system node
        emitting: Whether to emit particles (default: True)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, particle_path]):
        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,
            "particlePath": particle_path,
            "emitting": emitting,
        }

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

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

        state = "started" if emitting else "stopped"
        return f"Particle emission {state} for '{particle_path}'."

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