"""Audio Domain Tools for Godot MCP.

This module provides MCP tools for audio-related operations in Godot projects,
including adding audio players, setting audio streams, and configuring audio buses.
"""

import asyncio
from pathlib import Path

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

__all__ = [
    "audio_add_stream_player",
    "audio_set_stream",
    "audio_configure_bus",
]


@mcp.tool()
def audio_add_stream_player(
    project_path: str,
    scene_path: str,
    parent_node_path: str,
    player_name: str,
    player_type: str = "AudioStreamPlayer",
    autoplay: bool = False,
) -> str:
    """Add an audio stream player node to a scene.

    Category: Audio

    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
        player_name: Name for the new audio player node
        player_type: Type of player (AudioStreamPlayer, AudioStreamPlayer2D, AudioStreamPlayer3D, default: AudioStreamPlayer)
        autoplay: Whether to start playing automatically (default: False)

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

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

    valid_types = ["AudioStreamPlayer", "AudioStreamPlayer2D", "AudioStreamPlayer3D"]
    if player_type not in valid_types:
        return create_error_response(
            f"Invalid player type: {player_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,
            "playerName": player_name,
            "playerType": player_type,
            "autoplay": autoplay,
        }

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

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

        return f"Audio stream player '{player_name}' ({player_type}) added to '{parent_node_path}'."

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


@mcp.tool()
def audio_set_stream(
    project_path: str,
    scene_path: str,
    player_path: str,
    audio_file_path: str,
    volume_db: float = 0.0,
    pitch_scale: float = 1.0,
) -> str:
    """Set an audio stream for an audio player.

    Category: Audio

    Args:
        project_path: Path to the Godot project directory
        scene_path: Path to the scene file (relative to project)
        player_path: Path to the audio player node
        audio_file_path: Path to the audio file (relative to project, e.g., "sounds/music.ogg")
        volume_db: Volume in decibels (default: 0.0, range: -80 to 24)
        pitch_scale: Pitch scaling factor (default: 1.0, range: 0.01 to 4.0)

    Returns:
        Success message or error description
    """
    if not all([project_path, scene_path, player_path, audio_file_path]):
        return create_error_response("All parameters except volume_db and pitch_scale are required")

    if not validate_path(project_path) or not validate_path(scene_path) or not validate_path(audio_file_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}")

        audio_full_path = Path(project_path) / audio_file_path
        if not audio_full_path.exists():
            return create_error_response(
                f"Audio file does not exist: {audio_file_path}",
                ["Ensure the audio file path is correct"],
            )

        params = {
            "scenePath": scene_path,
            "playerPath": player_path,
            "audioFilePath": audio_file_path,
            "volumeDb": volume_db,
            "pitchScale": pitch_scale,
        }

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

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

        return f"Audio stream '{audio_file_path}' set for player '{player_path}'."

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


@mcp.tool()
def audio_configure_bus(
    project_path: str,
    bus_name: str,
    volume_db: float | None = None,
    mute: bool | None = None,
    solo: bool | None = None,
) -> str:
    """Configure an audio bus in the project.

    Category: Audio

    Args:
        project_path: Path to the Godot project directory
        bus_name: Name of the audio bus (e.g., "Master", "Music", "SFX")
        volume_db: Volume in decibels (range: -80 to 24)
        mute: Whether to mute the bus
        solo: Whether to solo the bus (mute all other buses)

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

    if all(param is None for param in [volume_db, mute, solo]):
        return create_error_response("At least one configuration parameter must be specified")

    if not validate_path(project_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 = {
            "busName": bus_name,
        }

        if volume_db is not None:
            params["volumeDb"] = volume_db
        if mute is not None:
            params["mute"] = mute
        if solo is not None:
            params["solo"] = solo

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

        if stderr and ("Failed to" in stderr or "[ERROR]" in stderr):
            return create_error_response(f"Failed to configure audio bus: {stderr}")

        return f"Audio bus '{bus_name}' configured successfully."

    except Exception as error:
        return create_error_response(f"Failed to configure audio bus: {error}")
