#!/bin/bash
# transition-detect: Detect track transitions via energy/spectral changes
# Usage:
#   transition-detect <audio_file> [sensitivity=6] [interval=10]
#   transition-detect --multi <file1> <file2> ... [-- sensitivity interval]
#   transition-detect --from-mix [mixfile.json] [-- sensitivity interval]
#
# Detects both:
#   - Silence gaps (traditional transitions) - requires ALL stems quiet
#   - Energy jumps (livecoding-style hot swaps)
#
# In multi mode, combines energy from all stems - better for livecoding sets
# where kick might drop but bass continues.

set -euo pipefail

# Defaults
SENSITIVITY=6
INTERVAL=10
MULTI_MODE=false
FILES=()

# Parse args
while [[ $# -gt 0 ]]; do
    case "$1" in
        --from-mix)
            # Load stems from .mix.json
            MIXFILE="${2:-${MIXFILE:-project.mix.json}}"
            if [[ -f "$MIXFILE" ]]; then
                MIXDIR=$(dirname "$MIXFILE")
                while IFS= read -r stem; do
                    if [[ -f "$MIXDIR/$stem" ]]; then
                        FILES+=("$MIXDIR/$stem")
                    fi
                done < <(jq -r '.stems[].file' "$MIXFILE")
                MULTI_MODE=true
                echo "# Loaded ${#FILES[@]} stems from $MIXFILE" >&2
            else
                echo "Error: Mix file not found: $MIXFILE" >&2
                exit 1
            fi
            shift 2 2>/dev/null || shift
            ;;
        --multi)
            MULTI_MODE=true
            shift
            ;;
        --)
            shift
            SENSITIVITY="${1:-6}"
            INTERVAL="${2:-10}"
            break
            ;;
        -*)
            echo "Unknown option: $1" >&2
            exit 1
            ;;
        *)
            if [[ -f "$1" ]]; then
                FILES+=("$1")
            elif [[ "$MULTI_MODE" == false && ${#FILES[@]} -eq 0 ]]; then
                # Single file mode, remaining args are sensitivity/interval
                FILES+=("$1")
                SENSITIVITY="${2:-6}"
                INTERVAL="${3:-10}"
                break
            else
                # Might be sensitivity/interval in multi mode without --
                if [[ ${#FILES[@]} -gt 0 ]] && [[ "$1" =~ ^[0-9]+$ ]]; then
                    SENSITIVITY="$1"
                    INTERVAL="${2:-10}"
                    break
                fi
            fi
            shift
            ;;
    esac
done

if [[ ${#FILES[@]} -eq 0 ]]; then
    echo "Usage: transition-detect <audio_file> [sensitivity] [interval]" >&2
    echo "       transition-detect --multi <file1> <file2> ... [-- sensitivity interval]" >&2
    echo "       transition-detect --from-mix [mixfile.json] [-- sensitivity interval]" >&2
    exit 1
fi

# Get duration from first file
DURATION=$(sox "${FILES[0]}" -n stat 2>&1 | grep "Length" | awk '{print int($3)}')

echo "# Transition detection"
echo "# Files: ${#FILES[@]} ($(basename "${FILES[0]}")$([ ${#FILES[@]} -gt 1 ] && echo ", ..."))"
echo "# Duration: ${DURATION}s, Sensitivity: ${SENSITIVITY}dB, Interval: ${INTERVAL}s"
echo "# Mode: $([ "$MULTI_MODE" == true ] || [ ${#FILES[@]} -gt 1 ] && echo "multi-stem (combined energy)" || echo "single-stem")"
echo "#"
echo "# TYPE       TIME       RMS_dB   DELTA    NOTES"

get_combined_rms() {
    local start=$1
    local dur=$2
    local max_rms=-100

    for file in "${FILES[@]}"; do
        local rms=$(sox "$file" -n trim "$start" "$dur" stats 2>&1 | grep "RMS lev dB" | awk '{print $4}')
        if [[ "$rms" != "-inf" ]] && (( $(echo "$rms > $max_rms" | bc -l 2>/dev/null || echo 0) )); then
            max_rms=$rms
        fi
    done
    echo "$max_rms"
}

is_all_silent() {
    local start=$1
    local dur=$2
    local threshold=${3:--50}

    for file in "${FILES[@]}"; do
        local rms=$(sox "$file" -n trim "$start" "$dur" stats 2>&1 | grep "RMS lev dB" | awk '{print $4}')
        if [[ "$rms" != "-inf" ]] && (( $(echo "$rms > $threshold" | bc -l 2>/dev/null || echo 0) )); then
            return 1  # Not silent
        fi
    done
    return 0  # All silent
}

prev_rms=""
prev_time=0

for ((i=0; i<DURATION; i+=INTERVAL)); do
    if [[ ${#FILES[@]} -gt 1 ]] || [[ "$MULTI_MODE" == true ]]; then
        rms=$(get_combined_rms "$i" "$INTERVAL")
    else
        rms=$(sox "${FILES[0]}" -n trim "$i" "$INTERVAL" stats 2>&1 | grep "RMS lev dB" | awk '{print $4}')
    fi

    # Handle silence (very low RMS)
    if [[ "$rms" == "-inf" ]] || [[ "$rms" == "-100" ]] || (( $(echo "$rms < -60" | bc -l 2>/dev/null || echo 0) )); then
        rms_val=-70
    else
        rms_val=$rms
    fi

    if [[ -n "$prev_rms" ]]; then
        if [[ "$prev_rms" == "-inf" ]] || (( $(echo "$prev_rms < -60" | bc -l 2>/dev/null || echo 0) )); then
            prev_val=-70
        else
            prev_val=$prev_rms
        fi

        delta=$(echo "$rms_val - $prev_val" | bc -l)
        abs_delta=$(echo "if ($delta < 0) -1*$delta else $delta" | bc -l)

        # Detect transitions
        if (( $(echo "$abs_delta > $SENSITIVITY" | bc -l) )); then
            time_fmt=$(printf '%02d:%02d:%02d' $((i/3600)) $(((i%3600)/60)) $((i%60)))

            if (( $(echo "$delta > 0" | bc -l) )); then
                type="ENERGY_UP"
                note="Track starts or builds"
            else
                type="ENERGY_DN"
                note="Track ends or drops"
            fi

            printf "%-10s %s  %7.1f  %+6.1f   %s\n" "$type" "$time_fmt" "$rms_val" "$delta" "$note"
        fi

        # Detect TRUE silence (all stems quiet)
        if [[ ${#FILES[@]} -gt 1 ]]; then
            if is_all_silent "$i" "$INTERVAL" && ! is_all_silent "$prev_time" "$INTERVAL"; then
                time_fmt=$(printf '%02d:%02d:%02d' $((i/3600)) $(((i%3600)/60)) $((i%60)))
                printf "%-10s %s  %7.1f  %+6.1f   %s\n" "SILENCE" "$time_fmt" "$rms_val" "$delta" "All stems silent"
            fi
        elif (( $(echo "$rms_val < -50 && $prev_val > -40" | bc -l) )); then
            time_fmt=$(printf '%02d:%02d:%02d' $((i/3600)) $(((i%3600)/60)) $((i%60)))
            printf "%-10s %s  %7.1f  %+6.1f   %s\n" "SILENCE" "$time_fmt" "$rms_val" "$delta" "Silence begins"
        fi
    fi

    prev_rms=$rms
    prev_time=$i
done
