#!/bin/bash
# mix-render: Render stems to a mixed output with optional processing
# Usage:
#   mix-render --from-mix <mixfile.json> [options]
#   mix-render <stem1.wav> <stem2.wav> ... -o output.wav
#
# Options:
#   --from-mix FILE    Read stems from mix.json
#   -o, --output FILE  Output filename (default: mix_output.wav)
#   --trim-silence     Trim silence from start/end
#   --normalize        Normalize output to -1dB peak
#   --fade-in SEC      Add fade in (default: 0)
#   --fade-out SEC     Add fade out (default: 2)
#   --format FMT       Output format: wav, flac, mp3 (default: wav)
#   --dry-run          Show what would be done without executing

set -euo pipefail

# Defaults
MIXFILE=""
OUTPUT="mix_output.flac"
TRIM_SILENCE=false
NORMALIZE=false
FADE_IN=0
FADE_OUT=2
FORMAT="flac"
DRY_RUN=false
FILES=()

# Parse args
while [[ $# -gt 0 ]]; do
    case "$1" in
        --from-mix)
            MIXFILE="$2"
            shift 2
            ;;
        -o|--output)
            OUTPUT="$2"
            shift 2
            ;;
        --trim-silence)
            TRIM_SILENCE=true
            shift
            ;;
        --normalize)
            NORMALIZE=true
            shift
            ;;
        --fade-in)
            FADE_IN="$2"
            shift 2
            ;;
        --fade-out)
            FADE_OUT="$2"
            shift 2
            ;;
        --format)
            FORMAT="$2"
            shift 2
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        -*)
            echo "Unknown option: $1" >&2
            exit 1
            ;;
        *)
            if [[ -f "$1" ]]; then
                FILES+=("$1")
            fi
            shift
            ;;
    esac
done

# Load stems from mix.json if specified
if [[ -n "$MIXFILE" ]]; then
    if [[ ! -f "$MIXFILE" ]]; then
        echo "Error: Mix file not found: $MIXFILE" >&2
        exit 1
    fi
    MIXDIR=$(dirname "$MIXFILE")
    while IFS= read -r stem; do
        if [[ -f "$MIXDIR/$stem" ]]; then
            FILES+=("$MIXDIR/$stem")
        fi
    done < <(jq -r '.stems[].file' "$MIXFILE")
    echo "Loaded ${#FILES[@]} stems from $MIXFILE"
fi

if [[ ${#FILES[@]} -eq 0 ]]; then
    echo "Usage: mix-render --from-mix <mixfile.json> [options]" >&2
    echo "       mix-render <stem1.wav> <stem2.wav> ... -o output.wav" >&2
    exit 1
fi

# Build sox command
SOX_ARGS=()

# Input files (mix)
SOX_ARGS+=("-m")
for f in "${FILES[@]}"; do
    SOX_ARGS+=("$f")
done

# Output - ensure correct extension
OUT_BASE="${OUTPUT%.*}"
case "$FORMAT" in
    wav)  OUTPUT="${OUT_BASE}.wav"; SOX_ARGS+=("$OUTPUT") ;;
    flac) OUTPUT="${OUT_BASE}.flac"; SOX_ARGS+=("$OUTPUT") ;;
    mp3)  OUTPUT="${OUT_BASE}.mp3"; SOX_ARGS+=("-t" "mp3" "$OUTPUT") ;;
esac

# Effects chain
EFFECTS=()

# Trim silence
if [[ "$TRIM_SILENCE" == true ]]; then
    EFFECTS+=("silence" "1" "0.1" "0.1%" "reverse" "silence" "1" "0.1" "0.1%" "reverse")
fi

# Normalize (always recommended after mixing as sox -m divides by input count)
if [[ "$NORMALIZE" == true ]]; then
    EFFECTS+=("norm" "-1")
else
    # Even without explicit normalize, compensate for sox -m level reduction
    EFFECTS+=("gain" "10")  # Roughly compensate for 12 stems
fi

# Fades
if (( $(echo "$FADE_IN > 0" | bc -l) )); then
    EFFECTS+=("fade" "t" "$FADE_IN")
fi
if (( $(echo "$FADE_OUT > 0" | bc -l) )); then
    # Get duration for fade out
    DUR=$(sox "${FILES[0]}" -n stat 2>&1 | grep "Length" | awk '{print $3}')
    EFFECTS+=("fade" "t" "0" "$DUR" "$FADE_OUT")
fi

if [[ "$DRY_RUN" == true ]]; then
    echo "Would run:"
    echo "sox ${SOX_ARGS[*]} ${EFFECTS[*]}"
else
    echo "Mixing ${#FILES[@]} stems..."
    echo "Output: $OUTPUT"
    sox "${SOX_ARGS[@]}" "${EFFECTS[@]}"

    # Show output stats
    echo ""
    echo "=== Output stats ==="
    sox "$OUTPUT" -n stats 2>&1 | grep -E "Length|RMS lev|Pk lev"
fi
