"""CPU-friendly faster-whisper entry point used by the Go media worker.

The process writes JSON only to stdout. Model/runtime diagnostics go to stderr so
the Go caller never mistakes logs for transcript data.
"""

from __future__ import annotations

import json
import os
import sys
import tempfile


def configure_model_cache() -> None:
    cache_root = os.getenv("JCF_ASR_CACHE_DIR") or os.path.join(tempfile.gettempdir(), "jcf-asr-cache")
    os.makedirs(cache_root, mode=0o700, exist_ok=True)
    hf_home = os.getenv("HF_HOME") or os.path.join(cache_root, "huggingface")
    os.makedirs(hf_home, mode=0o700, exist_ok=True)
    os.environ.setdefault("XDG_CACHE_HOME", cache_root)
    os.environ.setdefault("HF_HOME", hf_home)


def main() -> int:
    if len(sys.argv) < 2:
        print(json.dumps({"error": "missing_audio_path", "segments": []}, ensure_ascii=False))
        return 2

    configure_model_cache()

    from faster_whisper import WhisperModel

    audio_path = sys.argv[1]
    language = (sys.argv[2] if len(sys.argv) > 2 else "").strip() or None
    model_name = os.getenv("FASTER_WHISPER_MODEL_PATH") or os.getenv("FASTER_WHISPER_MODEL_SIZE", "small")
    device = os.getenv("FASTER_WHISPER_DEVICE", "cpu")
    compute_type = os.getenv("FASTER_WHISPER_COMPUTE_TYPE", "int8")
    model = WhisperModel(model_name, device=device, compute_type=compute_type)
    segments, info = model.transcribe(
        audio_path,
        language=language,
        beam_size=5,
        best_of=5,
        temperature=0.0,
        condition_on_previous_text=True,
        vad_filter=True,
        vad_parameters={"min_silence_duration_ms": 700},
        word_timestamps=True,
    )
    result = []
    for segment in segments:
        text = (segment.text or "").strip()
        if not text:
            continue
        words = []
        probabilities = []
        for word in segment.words or []:
            if word.start is None or word.end is None or not word.word:
                continue
            probability = float(word.probability) if word.probability is not None else None
            if probability is not None:
                probabilities.append(probability)
            words.append({
                "start": round(float(word.start), 3),
                "end": round(float(word.end), 3),
                "text": str(word.word),
                "probability": round(probability, 4) if probability is not None else None,
            })
        mean_probability = sum(probabilities) / len(probabilities) if probabilities else None
        avg_logprob = float(getattr(segment, "avg_logprob", -1.0) or -1.0)
        no_speech = float(getattr(segment, "no_speech_prob", 0.0) or 0.0)
        confidence = max(0.0, min(1.0, (1.0 + avg_logprob) * 0.45 + (1.0 - no_speech) * 0.2 + (mean_probability if mean_probability is not None else max(0.0, 1.0 + avg_logprob)) * 0.35))
        result.append({
            "start": round(float(segment.start), 3),
            "end": round(float(segment.end), 3),
            "text": text,
            "words": words,
            "confidence": round(confidence, 3),
            "needs_review": confidence < 0.62 or (mean_probability is not None and mean_probability < 0.55),
        })
    print(json.dumps({"language": getattr(info, "language", language), "segments": result}, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
