"""Cross-platform asynchronous sound playback for notification alerts.

Windows: uses winsound.PlaySound (stdlib, no dependencies).
Linux:   uses paplay (PulseAudio) or aplay (ALSA) via subprocess.

All playback is fire-and-forget on a background thread. A new notification
sound cancels any currently playing sound to prevent overlap.
"""

import subprocess
import sys
import threading
from pathlib import Path

from wled_controller.utils import get_logger

logger = get_logger(__name__)

# Lock + handle for cancelling previous sound
_play_lock = threading.Lock()
_current_process: subprocess.Popen | None = None


def _play_windows(file_path: Path, volume: float) -> None:
    """Play a WAV file on Windows using winsound."""
    import winsound

    # winsound doesn't support volume control natively,
    # but SND_ASYNC plays non-blocking within this thread
    try:
        winsound.PlaySound(str(file_path), winsound.SND_FILENAME | winsound.SND_ASYNC)
    except Exception as e:
        logger.error(f"winsound playback failed: {e}")


def _play_linux(file_path: Path, volume: float) -> None:
    """Play a sound file on Linux using paplay or aplay."""
    global _current_process

    # Cancel previous sound
    with _play_lock:
        if _current_process is not None:
            try:
                _current_process.terminate()
            except OSError as e:
                logger.debug("Failed to terminate previous sound process: %s", e)
                pass
            _current_process = None

    try:
        # Try paplay first (PulseAudio/PipeWire) — supports volume
        pa_volume = max(0, min(65536, int(volume * 65536)))
        proc = subprocess.Popen(
            ["paplay", f"--volume={pa_volume}", str(file_path)],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )
    except FileNotFoundError:
        try:
            # Fallback to aplay (ALSA) — no volume control
            proc = subprocess.Popen(
                ["aplay", "-q", str(file_path)],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            )
        except FileNotFoundError:
            logger.warning("Neither paplay nor aplay found — cannot play notification sound")
            return

    with _play_lock:
        _current_process = proc

    # Wait for completion
    proc.wait()

    with _play_lock:
        if _current_process is proc:
            _current_process = None


def play_sound_async(file_path: Path, volume: float = 1.0) -> None:
    """Play a sound file asynchronously (fire-and-forget).

    Args:
        file_path: Path to the sound file (.wav).
        volume: Volume level 0.0-1.0 (best-effort, not all backends support it).
    """
    if not file_path.exists():
        logger.warning(f"Sound file not found: {file_path}")
        return

    volume = max(0.0, min(1.0, volume))

    if sys.platform == "win32":
        player = _play_windows
    else:
        player = _play_linux

    thread = threading.Thread(
        target=player,
        args=(file_path, volume),
        name="sound-player",
        daemon=True,
    )
    thread.start()


def stop_current_sound() -> None:
    """Stop any currently playing notification sound."""
    if sys.platform == "win32":
        try:
            import winsound
            winsound.PlaySound(None, winsound.SND_PURGE)
        except Exception as e:
            logger.debug("Failed to stop winsound playback: %s", e)
            pass
    else:
        with _play_lock:
            global _current_process
            if _current_process is not None:
                try:
                    _current_process.terminate()
                except OSError as e:
                    logger.debug("Failed to terminate sound process: %s", e)
                    pass
                _current_process = None
