#!/usr/bin/python3
"""preflight.py - detect HVN Voice Capture's capabilities and what's missing, with
copy-paste setup instructions. Pure stdlib (runs on /usr/bin/python3, no deps), so it
works on ANY Mac, even one without Claude Code or Jason's full system.

Capability tiers (the app degrades gracefully):
  core         recording          needs macOS 14.2+ and ffmpeg (only hard requirements)
  transcribe   local transcripts  Parakeet or mlx-whisper (optional; Otter cloud is an alt)
  diarize      who-spoke-when     pyannote.audio + a Hugging Face token (optional)
  speakers     named speakers     a voiceprint library (optional; Jason's full system)
  integrate    automation         Claude Code present (optional; powers the skills)

Usage:  preflight.py            human report
        preflight.py --json     machine report for the app UI
"""
import json, os, platform, shutil, subprocess, sys

HOME = os.path.expanduser("~")
CANDIDATE_PYS = [
    f"{HOME}/.pyenv/versions/3.12.8/bin/python",
    f"{HOME}/.pyenv/shims/python3",
    shutil.which("python3") or "/usr/bin/python3",
]
BREW_PATHS = ["/opt/homebrew/bin", "/usr/local/bin"]


def which(cmd):
    p = shutil.which(cmd)
    if p:
        return p
    for d in BREW_PATHS + [f"{HOME}/.pyenv/versions/3.12.8/bin"]:
        cand = os.path.join(d, cmd)
        if os.path.exists(cand):
            return cand
    return None


def module_in_any_py(mod):
    for py in CANDIDATE_PYS:
        if py and os.path.exists(py):
            try:
                r = subprocess.run([py, "-c", f"import importlib.util,sys;sys.exit(0 if importlib.util.find_spec('{mod}') else 1)"],
                                   capture_output=True, timeout=8)
                if r.returncode == 0:
                    return py
            except Exception:
                pass
    return None


def macos_ok():
    v = platform.mac_ver()[0] or "0"
    parts = [int(x) for x in v.split(".")[:2]] + [0, 0]
    major, minor = parts[0], parts[1]
    ok = major > 14 or (major == 14 and minor >= 2)
    return ok, v


def hf_token():
    if os.environ.get("HF_TOKEN") or os.environ.get("HUGGING_FACE_HUB_TOKEN"):
        return True
    return os.path.exists(f"{HOME}/.cache/huggingface/token")


def voiceprint_count():
    f = f"{HOME}/.claude/artifacts/hvn-voiceprints/voiceprints.json"
    if not os.path.exists(f):
        return None
    try:
        return len(json.load(open(f)).get("speakers", {}))
    except Exception:
        return 0


def build():
    caps = []
    osok, osv = macos_ok()
    caps.append({"key": "macos", "tier": "core", "label": "macOS 14.2+ (audio capture)",
                 "ok": osok, "detail": f"macOS {osv}",
                 "fix": "Core Audio taps need macOS 14.2 or later. Update macOS in System Settings."})

    ff = which("ffmpeg")
    caps.append({"key": "ffmpeg", "tier": "core", "label": "Recording + encoding (ffmpeg)",
                 "ok": bool(ff), "detail": ff or "not found",
                 "fix": "brew install ffmpeg   (install Homebrew first from https://brew.sh)"})

    par = which("parakeet-mlx")
    mlx = module_in_any_py("mlx_whisper")
    caps.append({"key": "transcribe", "tier": "transcribe", "label": "Local transcription (Parakeet / mlx-whisper)",
                 "ok": bool(par or mlx), "detail": ("parakeet-mlx" if par else ("mlx_whisper" if mlx else "none")),
                 "fix": "pip install parakeet-mlx   (Python 3.12+; or pip install mlx-whisper). "
                        "No install needed if you transcribe with Otter instead."})

    py = module_in_any_py("pyannote.audio")
    caps.append({"key": "diarize", "tier": "diarize", "label": "Speaker diarization (pyannote)",
                 "ok": bool(py), "detail": (py or "not installed"),
                 "fix": "pip install pyannote.audio  (Python 3.12+), then accept the 3 gated model "
                        "licenses on huggingface.co (speaker-diarization-3.1, segmentation-3.0, community-1)."})

    caps.append({"key": "hf_token", "tier": "diarize", "label": "Diarization access token (Hugging Face)",
                 "ok": hf_token(), "detail": "present" if hf_token() else "not set",
                 "fix": "Create a token at huggingface.co/settings/tokens, then: export HF_TOKEN=... "
                        "(or run: huggingface-cli login). Only needed for local diarization."})

    n = voiceprint_count()
    caps.append({"key": "speakers", "tier": "speakers", "label": "Named-speaker library (voiceprints)",
                 "ok": n is not None and n > 0, "detail": (f"{n} speakers enrolled" if n else "no library yet"),
                 "fix": "Enroll voices in the Speakers tab, or import a shared library "
                        "(Settings -> Import speakers from file/URL)."})

    cc = bool(which("claude") or os.path.isdir(f"{HOME}/.claude"))
    caps.append({"key": "integrate", "tier": "integrate", "label": "Claude Code automation (optional)",
                 "ok": cc, "detail": "available" if cc else "not detected",
                 "fix": "Optional. With Claude Code, the meeting-transcription and board-notes skills "
                        "can run transcription/diarization and file results automatically."})

    core_ok = all(c["ok"] for c in caps if c["tier"] == "core")
    return {"core_ready": core_ok, "capabilities": caps}


def human(report):
    print("HVN Voice Capture - capability check\n")
    mark = {True: "OK ", False: "-- "}
    for c in report["capabilities"]:
        print(f"  [{mark[c['ok']]}] {c['label']}  ({c['detail']})")
        if not c["ok"]:
            print(f"        setup: {c['fix']}")
    print(f"\nCore recording ready: {'YES' if report['core_ready'] else 'NO (install the core items above)'}")


if __name__ == "__main__":
    rep = build()
    if "--json" in sys.argv:
        print(json.dumps(rep))
    else:
        human(rep)
