#!/bin/bash
# mix-master: Apply mastering chain to audio
# Usage:
#   mix-master <input.wav> -o <output.wav> [options]
#
# Mastering chain (based on rhadamanthe_techno tips):
#   1. EQ extreme (cut <20Hz and >20kHz)
#   2. Bass mono (mono everything below 200Hz)
#   3. Compression (glue compressor)
#   4. Limiting (to target LUFS)
#
# Options:
#   -o, --output FILE      Output filename (required)
#   --target-lufs N        Target LUFS (default: -14 for streaming, -8 for club)
#   --low-cut HZ           Low cut frequency (default: 20)
#   --high-cut HZ          High cut frequency (default: 20000)
#   --bass-mono HZ         Mono bass below this freq (default: 200)
#   --no-limit             Skip limiter (just EQ + bass mono)
#   --preset NAME          Use preset: streaming, club, loud
#   --dry-run              Show ffmpeg command without running

set -euo pipefail

# Source progress utilities
SCRIPT_DIR="$(dirname "$0")"
if [[ -f "$SCRIPT_DIR/lib/progress.sh" ]]; then
    source "$SCRIPT_DIR/lib/progress.sh"
fi

INPUT=""
OUTPUT=""
TARGET_LUFS=-14
LOW_CUT=20
HIGH_CUT=20000
BASS_MONO=200
NO_LIMIT=false
DRY_RUN=false

while [[ $# -gt 0 ]]; do
    case "$1" in
        -o|--output)
            OUTPUT="$2"
            shift 2
            ;;
        --target-lufs)
            TARGET_LUFS="$2"
            shift 2
            ;;
        --low-cut)
            LOW_CUT="$2"
            shift 2
            ;;
        --high-cut)
            HIGH_CUT="$2"
            shift 2
            ;;
        --bass-mono)
            BASS_MONO="$2"
            shift 2
            ;;
        --no-limit)
            NO_LIMIT=true
            shift
            ;;
        --preset)
            case "$2" in
                streaming)
                    TARGET_LUFS=-14
                    ;;
                club)
                    TARGET_LUFS=-8
                    ;;
                loud)
                    TARGET_LUFS=-6
                    ;;
                *)
                    echo "Unknown preset: $2 (use: streaming, club, loud)" >&2
                    exit 1
                    ;;
            esac
            shift 2
            ;;
        --dry-run)
            DRY_RUN=true
            shift
            ;;
        -*)
            echo "Unknown option: $1" >&2
            exit 1
            ;;
        *)
            if [[ -z "$INPUT" ]] && [[ -f "$1" ]]; then
                INPUT="$1"
            fi
            shift
            ;;
    esac
done

if [[ -z "$INPUT" ]] || [[ -z "$OUTPUT" ]]; then
    echo "Usage: mix-master <input.wav> -o <output.wav> [options]" >&2
    echo ""
    echo "Presets:"
    echo "  --preset streaming  -14 LUFS (SoundCloud, Spotify)"
    echo "  --preset club       -8 LUFS (DJ/club play)"
    echo "  --preset loud       -6 LUFS (maximum loudness)"
    exit 1
fi

echo "=== Mastering Chain ==="
echo "Input: $INPUT"
echo "Output: $OUTPUT"
echo ""
echo "Settings:"
echo "  Low cut: ${LOW_CUT}Hz"
echo "  High cut: ${HIGH_CUT}Hz"
echo "  Bass mono below: ${BASS_MONO}Hz"
echo "  Target LUFS: $TARGET_LUFS"
echo ""

# Build filter chain
FILTERS=""

# 1. EQ extreme - cut sub and ultra-high
FILTERS+="highpass=f=${LOW_CUT}:poles=2,"
FILTERS+="lowpass=f=${HIGH_CUT}:poles=2,"

# 2. Bass mono - convert low frequencies to mono
# Using crossfeed technique: extract bass, mono it, add back
FILTERS+="pan=stereo|c0=c0|c1=c1,"  # passthrough first
# Split into low (mono) and high (stereo)
FILTERS+="channelsplit=channel_layout=stereo[L][R];"
FILTERS+="[L]lowpass=f=${BASS_MONO}[Llow];"
FILTERS+="[R]lowpass=f=${BASS_MONO}[Rlow];"
FILTERS+="[Llow][Rlow]amerge=inputs=2,pan=mono|c0=0.5*c0+0.5*c1[mono_bass];"
FILTERS+="[L]highpass=f=${BASS_MONO}[Lhigh];"
FILTERS+="[R]highpass=f=${BASS_MONO}[Rhigh];"
FILTERS+="[mono_bass]asplit[bass_l][bass_r];"
FILTERS+="[Lhigh][bass_l]amix=inputs=2:duration=first[Lfinal];"
FILTERS+="[Rhigh][bass_r]amix=inputs=2:duration=first[Rfinal];"
FILTERS+="[Lfinal][Rfinal]amerge=inputs=2,pan=stereo|c0=c0|c1=c1"

# Actually, that's getting complex. Let's use a simpler approach with sox
# Switching to sox for better audio quality

# Build sox effects
SOX_EFFECTS=""

# 1. High pass (low cut)
SOX_EFFECTS+="highpass $LOW_CUT "

# 2. Low pass (high cut)
SOX_EFFECTS+="lowpass $HIGH_CUT "

# 3. Compressor (glue)
SOX_EFFECTS+="compand 0.3,1 6:-70,-60,-20 -5 -90 0.2 "

# For bass mono, we'd need more complex processing
# Skip for now, can add with ffmpeg separately

if [[ "$NO_LIMIT" == false ]]; then
    # 4. Limiter via loudnorm
    LIMITER_CMD="ffmpeg -y -i TEMP_FILE -af loudnorm=I=${TARGET_LUFS}:TP=-1:LRA=11 OUTPUT_FILE"
fi

if [[ "$DRY_RUN" == true ]]; then
    echo "Would run:"
    echo "sox \"$INPUT\" temp_master.wav $SOX_EFFECTS"
    if [[ "$NO_LIMIT" == false ]]; then
        echo "ffmpeg -y -i temp_master.wav -af loudnorm=I=${TARGET_LUFS}:TP=-1:LRA=11 \"$OUTPUT\""
    fi
    exit 0
fi

# Run mastering chain
TEMP_FILE=$(mktemp --suffix=.wav)

# Get input duration for progress tracking
DURATION=$(sox "$INPUT" -n stat 2>&1 | grep "Length" | awk '{print $3}')
DURATION_FMT=$(printf '%02d:%02d:%02d' $((${DURATION%.*}/3600)) $(((${DURATION%.*}%3600)/60)) $((${DURATION%.*}%60)))
echo "Duration: $DURATION_FMT"
echo ""

START_TIME=$(date +%s)

echo "Step 1/3: EQ + Compression..."
sox "$INPUT" "$TEMP_FILE" $SOX_EFFECTS 2>/dev/null
STEP1_TIME=$(date +%s)
echo "  Done in $((STEP1_TIME - START_TIME))s"

if [[ "$NO_LIMIT" == false ]]; then
    echo "Step 2/3: Loudness normalization to ${TARGET_LUFS} LUFS..."
    echo "  (this takes ~${DURATION_FMT} at 25-30x speed, ETA ~$((${DURATION%.*} / 28))s)"

    ffmpeg -y -progress pipe:1 -i "$TEMP_FILE" -af "loudnorm=I=${TARGET_LUFS}:TP=-1:LRA=11" "$OUTPUT" 2>/dev/null | \
    while IFS='=' read -r key value; do
        if [[ "$key" == "out_time_us" && -n "$value" && "$value" != "N/A" ]]; then
            current_secs=$((value / 1000000))
            pct=$((current_secs * 100 / ${DURATION%.*}))
            elapsed=$(($(date +%s) - STEP1_TIME))
            if [[ $current_secs -gt 0 ]]; then
                eta=$(( (${DURATION%.*} - current_secs) * elapsed / current_secs ))
            else
                eta=0
            fi
            printf "\r  Progress: %3d%% | ETA: %ds     " "$pct" "$eta"
        fi
    done
    echo ""
    rm "$TEMP_FILE"
else
    mv "$TEMP_FILE" "$OUTPUT"
fi

STEP2_TIME=$(date +%s)
echo "Step 3/3: Analyzing output..."

ffmpeg -progress pipe:1 -i "$OUTPUT" -af loudnorm=print_format=json -f null - 2>&1 | \
while IFS='=' read -r key value; do
    if [[ "$key" == "out_time_us" && -n "$value" && "$value" != "N/A" ]]; then
        current_secs=$((value / 1000000))
        pct=$((current_secs * 100 / ${DURATION%.*}))
        printf "\r  Analyzing: %3d%%     " "$pct"
    fi
done
echo ""

FINAL_STATS=$(ffmpeg -i "$OUTPUT" -af loudnorm=print_format=json -f null - 2>&1 | grep -A12 "input_i")
echo ""
echo "=== Output Stats ==="
echo "$FINAL_STATS" | grep -E "input_i|input_tp|input_lra" | sed 's/[",]//g; s/^[ \t]*/  /'

TOTAL_TIME=$(($(date +%s) - START_TIME))
echo ""
echo "Done: $OUTPUT"
echo "Total time: ${TOTAL_TIME}s"
ls -lh "$OUTPUT" | awk '{print "File size: " $5}'
