#!/usr/bin/env python3
"""Batch sonic/spectral analysis of all audio files in a directory.
Outputs a summary and saves per-track JSON results.

Usage: python3 batch_analyze.py "/path/to/music/folder"
"""

import os, sys, json
import numpy as np
import librosa
from collections import Counter

def analyze_folder(music_dir: str):
    exts = ('.mp3', '.flac', '.m4a', '.ogg', '.wav')
    files = sorted(f for f in os.listdir(music_dir) if f.lower().endswith(exts))
    if not files:
        print("No audio files found.")
        return

    results = []
    for i, f in enumerate(files):
        path = os.path.join(music_dir, f)
        try:
            y, sr = librosa.load(path, sr=22050, duration=45)
            tempo = librosa.feature.rhythm.tempo(y=y, sr=sr)[0]
            rms = float(np.nanmean(librosa.feature.rms(y=y)[0]))
            centroid = float(np.nanmean(librosa.feature.spectral_centroid(y=y, sr=sr)[0]))
            zcr = float(np.nanmean(librosa.feature.zero_crossing_rate(y=y)[0]))
            dur = float(librosa.get_duration(y=y, sr=sr))
            chroma = librosa.feature.chroma_cqt(y=y, sr=sr).mean(axis=1)
            keys = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']
            key = keys[int(np.argmax(chroma))]
            results.append({
                'file': f,
                'tempo': round(tempo, 1),
                'rms': round(rms, 4),
                'centroid': round(centroid, 1),
                'zcr': round(zcr, 4),
                'duration': round(dur, 1),
                'key': key,
            })
        except Exception as e:
            results.append({'file': f, 'error': str(e)})

    good = [r for r in results if 'tempo' in r]
    bad = [r for r in results if 'error' in r]

    tempos = [r['tempo'] for r in good]
    energies = [r['rms'] for r in good]
    centroids = [r['centroid'] for r in good]
    durations = [r['duration'] for r in good]
    keys = [r['key'] for r in good]
    kc = Counter(keys)

    folder_name = os.path.basename(music_dir.rstrip('/'))
    print(f"=== {folder_name} — SONIC ANALYSIS ===")
    print(f"Total files: {len(files)} | Analyzed: {len(good)} | Errors: {len(bad)}")
    if bad:
        for r in bad:
            print(f"  ✗ {r['file']}: {r['error']}")

    print(f"\n--- COLLECTIVE STATS ---")
    print(f"Tempo:     mean={np.mean(tempos):.1f}  std={np.std(tempos):.1f}  min={min(tempos):.1f}  max={max(tempos):.1f}")
    print(f"Energy:    mean={np.mean(energies):.4f}  std={np.std(energies):.4f}")
    print(f"Brightness (centroid): mean={np.mean(centroids):.0f} Hz  std={np.std(centroids):.0f} Hz")
    print(f"Duration:  mean={np.mean(durations):.1f}s  total={sum(durations)/60:.1f} min")

    print(f"\n--- KEY DISTRIBUTION ---")
    for k, _ in kc.most_common():
        print(f"  {k}: {kc[k]}")

    print(f"\n--- FASTEST ---")
    for r in sorted(good, key=lambda x: x['tempo'], reverse=True)[:5]:
        print(f"  {r['tempo']:.0f} BPM — {r['file']}")

    print(f"\n--- SLOWEST ---")
    for r in sorted(good, key=lambda x: x['tempo'])[:5]:
        print(f"  {r['tempo']:.0f} BPM — {r['file']}")

    print(f"\n--- HIGHEST ENERGY ---")
    for r in sorted(good, key=lambda x: x['rms'], reverse=True)[:5]:
        print(f"  {r['rms']:.4f} — {r['file']}")

    print(f"\n--- BRIGHTEST (highest centroid) ---")
    for r in sorted(good, key=lambda x: x['centroid'], reverse=True)[:5]:
        print(f"  {r['centroid']:.0f} Hz — {r['file']}")

    print(f"\n--- DARKEST (lowest centroid) ---")
    for r in sorted(good, key=lambda x: x['centroid'])[:5]:
        print(f"  {r['centroid']:.0f} Hz — {r['file']}")

    out_path = f"/tmp/{folder_name.replace(' ', '_')}_sonic_results.json"
    with open(out_path, "w") as fh:
        json.dump(results, fh, indent=2, ensure_ascii=False)
    print(f"\n\nFull results saved to {out_path}")


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} /path/to/music/folder")
        sys.exit(1)
    analyze_folder(sys.argv[1])
