import logging
import tempfile
from pathlib import Path

import librosa
import numpy as np
import soundfile as sf

logger = logging.getLogger(__name__)

# Map bit depth to soundfile subtype
_BIT_DEPTH_SUBTYPE = {
    16: "PCM_16",
    24: "PCM_24",
    32: "FLOAT",
}


def load_audio(path: Path) -> tuple[np.ndarray, int]:
    """Load an audio file and return (data, sample_rate).

    Data is returned as float32, shape (samples,) for mono or (samples, channels) for stereo.
    """
    data, sr = sf.read(str(path), dtype="float32", always_2d=True)
    logger.debug("Loaded %s: %d samples, %d channels, %d Hz", path.name, data.shape[0], data.shape[1], sr)
    return data, sr


def save_audio(path: Path, audio: np.ndarray, sr: int, bits: int = 16) -> None:
    """Save audio as WAV with the specified bit depth."""
    subtype = _BIT_DEPTH_SUBTYPE.get(bits)
    if subtype is None:
        raise ValueError(f"Unsupported bit depth: {bits}. Use 16, 24, or 32.")
    sf.write(str(path), audio, sr, subtype=subtype)
    logger.info("Saved %s (%d Hz, %d-bit)", path.name, sr, bits)


def resample(audio: np.ndarray, sr_orig: int, sr_target: int) -> np.ndarray:
    """Resample audio via librosa if sample rates differ."""
    if sr_orig == sr_target:
        return audio
    logger.debug("Resampling from %d Hz to %d Hz", sr_orig, sr_target)
    # librosa expects (channels, samples) for multi-channel
    if audio.ndim == 2:
        resampled = np.stack(
            [librosa.resample(audio[:, ch], orig_sr=sr_orig, target_sr=sr_target) for ch in range(audio.shape[1])],
            axis=1,
        )
    else:
        resampled = librosa.resample(audio, orig_sr=sr_orig, target_sr=sr_target)
    return resampled


def create_temp_wav(audio: np.ndarray, sr: int) -> Path:
    """Write audio to a temporary WAV file and return the path.

    Caller is responsible for cleanup.
    """
    fd = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
    fd.close()
    path = Path(fd.name)
    sf.write(str(path), audio, sr, subtype="FLOAT")
    logger.debug("Created temp WAV: %s", path)
    return path
