#!/usr/bin/env python3
"""
Audio Instrumental Generator
Creates instrumental.wav files by subtracting vox.wav from mixture.wav
"""

import librosa
import soundfile as sf
import numpy as np
from pathlib import Path
import argparse


def create_instrumental(song_folder):
    """
    Create instrumental.wav by subtracting vox.wav from mixture.wav

    Args:
        song_folder (str): Path to the song folder containing stems
    """
    song_path = Path(song_folder)
    mixture_path = song_path / "mixture.wav"
    vox_path = song_path / "vox.wav"
    instrumental_path = song_path / "instrumental.wav"

    # Check if required files exist
    if not mixture_path.exists():
        print(f"Warning: {mixture_path} not found, skipping {song_path.name}")
        return False

    if not vox_path.exists():
        print(f"Warning: {vox_path} not found, skipping {song_path.name}")
        return False

    # Check if instrumental already exists
    if instrumental_path.exists():
        print(f"Instrumental already exists for {song_path.name}, skipping")
        return True

    try:
        # Load audio files
        print(f"Processing {song_path.name}...")
        mixture, sr_mix = librosa.load(str(mixture_path), sr=None, mono=False)
        vox, sr_vox = librosa.load(str(vox_path), sr=None, mono=False)

        # Ensure sample rates match
        if sr_mix != sr_vox:
            print(
                f"Warning: Sample rate mismatch in {song_path.name} (mixture: {sr_mix}, vox: {sr_vox})"
            )
            # Resample vox to match mixture
            vox = librosa.resample(vox, orig_sr=sr_vox, target_sr=sr_mix)

        # Handle mono/stereo differences
        if mixture.ndim != vox.ndim:
            if mixture.ndim == 1 and vox.ndim == 2:
                mixture = np.array([mixture, mixture])  # Convert mono to stereo
            elif mixture.ndim == 2 and vox.ndim == 1:
                vox = np.array([vox, vox])  # Convert mono to stereo

        # Ensure same length by padding or truncating
        min_length = min(mixture.shape[-1], vox.shape[-1])
        if mixture.ndim == 1:
            mixture = mixture[:min_length]
            vox = vox[:min_length]
        else:
            mixture = mixture[:, :min_length]
            vox = vox[:, :min_length]

        # Create instrumental by subtraction
        instrumental = mixture - vox

        # Save the instrumental track
        sf.write(
            str(instrumental_path),
            instrumental.T if instrumental.ndim == 2 else instrumental,
            sr_mix,
        )
        print(f"Created instrumental for {song_path.name}")
        return True

    except Exception as e:
        print(f"Error processing {song_path.name}: {str(e)}")
        return False


def process_music_database(root_folder):
    """
    Process all song folders in the music database

    Args:
        root_folder (str): Root folder containing song subfolders
    """
    root_path = Path(root_folder)

    if not root_path.exists():
        print(f"Error: Root folder {root_folder} does not exist")
        return

    song_folders = [f for f in root_path.iterdir() if f.is_dir()]

    if not song_folders:
        print(f"No subfolders found in {root_folder}")
        return

    print(f"Found {len(song_folders)} song folders")
    processed = 0
    skipped = 0
    errors = 0

    for song_folder in sorted(song_folders):
        result = create_instrumental(song_folder)
        if result is True:
            processed += 1
        elif result is False:
            errors += 1
        else:
            skipped += 1

    print("\nSummary:")
    print(f"Processed: {processed}")
    print(f"Skipped: {skipped}")
    print(f"Errors: {errors}")


def main():
    parser = argparse.ArgumentParser(
        description="Generate instrumental tracks from audio stems"
    )
    parser.add_argument("root_folder", help="Root folder containing song subfolders")
    parser.add_argument("--song", help="Process only a specific song folder")

    args = parser.parse_args()

    if args.song:
        # Process single song
        song_path = Path(args.root_folder) / args.song
        if song_path.exists() and song_path.is_dir():
            create_instrumental(song_path)
        else:
            print(f"Song folder {song_path} not found")
    else:
        # Process all songs
        process_music_database(args.root_folder)


if __name__ == "__main__":
    main()
