"""Light Domain Tools for Godot MCP.

This module provides MCP tools for lighting-related operations in Godot projects,
primarily for 3D scenes including directional, point, and spot lights.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "light_add",
    "light_set_properties",
    "light_set_shadow",
    "environment_setup",
]


@mcp.tool()
def light_add(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    light_name: str,
    light_type: str = "DirectionalLight3D",
    energy: float = 1.0,
    color: str = "[1, 1, 1]",
) -> str:
    """Add a light source to a 3D scene.

    Category: Light

    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
        light_name: Name for the new light node
        light_type: Type of light (DirectionalLight3D, OmniLight3D, SpotLight3D, default: DirectionalLight3D)
                   Note: PointLight3D is deprecated in Godot 4.x, use OmniLight3D instead
        energy: Light energy/intensity (default: 1.0)
        color: Light color as JSON array [r, g, b] with values 0-1 (default: [1, 1, 1] white)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path, light_name]):
        return create_error_response("All parameters except light_type, energy, and color are required")

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

    valid_types = ["DirectionalLight3D", "PointLight3D", "SpotLight3D", "OmniLight3D"]
    if light_type not in valid_types:
        return create_error_response(
            f"Invalid light type: {light_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,
            "lightName": light_name,
            "lightType": light_type,
            "energy": energy,
            "color": color,
        }

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

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

        return f"Light '{light_name}' ({light_type}) added to '{parent_node_path}'."

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


@mcp.tool()
def light_set_properties(
    project_path: str,
    scene_path: str,
    light_path: str,
    energy: float | None = None,
    color: str | None = None,
    range: float | None = None,
    attenuation: float | None = None,
    spot_angle: float | None = None,
    spot_attenuation: float | None = None,
) -> str:
    """Set properties of a light source.

    Category: Light

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        light_path: Path to the light node
        energy: Light energy/intensity
        color: Light color as JSON array [r, g, b]
        range: Light range (for PointLight3D/SpotLight3D)
        attenuation: Attenuation curve (for PointLight3D/SpotLight3D)
        spot_angle: Spot angle in degrees (for SpotLight3D)
        spot_attenuation: Spot attenuation curve (for SpotLight3D)

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

    property_params = [energy, color, range, attenuation, spot_angle, spot_attenuation]
    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,
            "lightPath": light_path,
        }

        if energy is not None:
            params["energy"] = energy
        if color:
            params["color"] = color
        if range is not None:
            params["range"] = range
        if attenuation is not None:
            params["attenuation"] = attenuation
        if spot_angle is not None:
            params["spotAngle"] = spot_angle
        if spot_attenuation is not None:
            params["spotAttenuation"] = spot_attenuation

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

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

        return f"Light properties set for '{light_path}'."

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


@mcp.tool()
def light_set_shadow(
    project_path: str,
    scene_path: str,
    light_path: str,
    shadow_enabled: bool = True,
    shadow_bias: float | None = None,
    shadow_blur: float | None = None,
) -> str:
    """Configure shadow settings for a light source.

    Category: Light

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        light_path: Path to the light node
        shadow_enabled: Whether shadows are enabled (default: True)
        shadow_bias: Shadow bias to reduce shadow acne
        shadow_blur: Shadow blur amount

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, light_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,
            "lightPath": light_path,
            "shadowEnabled": shadow_enabled,
        }

        if shadow_bias is not None:
            params["shadowBias"] = shadow_bias
        if shadow_blur is not None:
            params["shadowBlur"] = shadow_blur

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

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

        return f"Shadow settings configured for light '{light_path}'."

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


@mcp.tool()
def environment_setup(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    environment_name: str = "WorldEnvironment",
    ambient_light_color: str | None = None,
    ambient_light_energy: float | None = None,
    background_mode: str = "Sky",
    sky_color: str | None = None,
) -> str:
    """Set up environment and ambient lighting for a 3D scene.

    Category: Light

    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
        environment_name: Name for the WorldEnvironment node (default: "WorldEnvironment")
        ambient_light_color: Ambient light color as JSON array [r, g, b]
        ambient_light_energy: Ambient light energy/intensity
        background_mode: Background mode (Sky, Color, Custom, default: Sky)
        sky_color: Sky color as JSON array [r, g, b] (for Color background mode)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, parent_node_path]):
        return create_error_response("project_path, scene_path, and parent_node_path 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}")

        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,
            "environmentName": environment_name,
            "backgroundMode": background_mode,
        }

        if ambient_light_color:
            params["ambientLightColor"] = ambient_light_color
        if ambient_light_energy is not None:
            params["ambientLightEnergy"] = ambient_light_energy
        if sky_color:
            params["skyColor"] = sky_color

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

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to setup environment: {stderr}")

        return f"Environment '{environment_name}' configured in '{parent_node_path}'."

    except Exception as error:
        return create_error_response(f"Failed to setup environment: {error}")
