#!/usr/bin/env python3
"""
analyze.py — clean JSON wrapper around Lux's audio_analyzer.

Usage:
  analyze.py /path/to/file.wav
  analyze.py --pond filename.wav     # analyze a file in the pond dir
  analyze.py --stdin                 # read base64 of a file from stdin

Emits a single JSON object on stdout with this schema:

  {
    "ok": true,
    "input": {
      "basename": "Freq-Bridge-Marcotone.wav",
      "bytes": 963985,
      "duration_seconds": 180.0
    },
    "description": "...",
    "features": { ... all numeric/feature fields ... }
  }

Designed to be called from a Bun API route via subprocess.
"""
import sys
import os
import json
import base64
import tempfile
import warnings
from pathlib import Path
import traceback

warnings.filterwarnings("ignore")

PROJECT = Path(__file__).resolve().parent
sys.path.insert(0, str(PROJECT))

import numpy as np
from audio_analyzer import extract_features, synthesize_description


def _featurize_for_json(features):
    """Strip numpy types, keep only JSON-safe values."""
    out = {}
    for k, v in features.items():
        if isinstance(v, np.ndarray):
            out[k] = v.tolist()
        elif isinstance(v, (np.float32, np.float64)):
            out[k] = float(v)
        elif isinstance(v, (np.int32, np.int64)):
            out[k] = int(v)
        elif isinstance(v, dict):
            out[k] = _featurize_for_json(v)
        elif isinstance(v, list):
            out[k] = [
                _featurize_for_json(x) if isinstance(x, dict)
                else (float(x) if isinstance(x, (np.floating,)) else x)
                for x in v
            ]
        else:
            out[k] = v
    return out


def analyze(path: str):
    path = os.path.abspath(path)
    if not os.path.exists(path):
        return {"ok": False, "error": f"File not found: {path}"}
    if os.path.getsize(path) == 0:
        return {"ok": False, "error": "File is empty"}

    try:
        features = extract_features(path)
        description = synthesize_description(features)
    except Exception as exc:
        return {
            "ok": False,
            "error": f"Analyzer raised: {exc}",
            "trace": traceback.format_exc(limit=4),
        }

    return {
        "ok": True,
        "input": {
            "basename": os.path.basename(path),
            "path": path,
            "bytes": os.path.getsize(path),
            "duration_seconds": features.get("duration"),
        },
        "description": description,
        "features": _featurize_for_json(features),
    }


def main():
    args = sys.argv[1:]
    cleanup_path = None

    if not args or args[0] in ("-h", "--help"):
        print(__doc__)
        sys.exit(0)

    if args[0] == "--pond":
        if len(args) < 2:
            print(json.dumps({"ok": False, "error": "--pond needs a filename"}))
            sys.exit(1)
        pond = PROJECT / "pond" / args[1]
        result = analyze(str(pond))
    elif args[0] == "--stdin":
        raw = sys.stdin.read().strip()
        try:
            data = base64.b64decode(raw)
        except Exception as exc:
            print(json.dumps({"ok": False, "error": f"Bad base64: {exc}"}))
            sys.exit(1)
        with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tf:
            tf.write(data)
            cleanup_path = tf.name
        result = analyze(cleanup_path)
    else:
        result = analyze(args[0])

    if cleanup_path and os.path.exists(cleanup_path):
        os.unlink(cleanup_path)

    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
