from __future__ import annotations

import argparse
import base64
import json
import math
import struct
import sys
import urllib.error
import urllib.request
import wave
from io import BytesIO


def post_json(url: str, payload: dict, timeout: int) -> dict:
    request = urllib.request.Request(
        url,
        data=json.dumps(payload, ensure_ascii=False).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urllib.request.urlopen(request, timeout=timeout) as response:
        data = json.loads(response.read().decode("utf-8"))
    if not isinstance(data, dict):
        raise ValueError(f"JSON object expected from {url}")
    return data


def make_wav_data_url(seconds: float = 1.0, sample_rate: int = 16000) -> str:
    frames = int(seconds * sample_rate)
    buffer = BytesIO()
    with wave.open(buffer, "wb") as wav:
        wav.setnchannels(1)
        wav.setsampwidth(2)
        wav.setframerate(sample_rate)
        for index in range(frames):
            envelope = 0.5 if 0.1 * sample_rate < index < 0.9 * sample_rate else 0.0
            sample = int(9000 * envelope * math.sin(2 * math.pi * 440 * index / sample_rate))
            wav.writeframesraw(struct.pack("<h", sample))
    return "data:audio/wav;base64," + base64.b64encode(buffer.getvalue()).decode("ascii")


def run(args: argparse.Namespace) -> int:
    payload = {
        "base_url": args.audio_base_url,
        "audio_base64": make_wav_data_url(args.seconds),
        "filename": "smoke-tone.wav",
        "language": args.language,
        "task": args.task,
    }
    result = post_json(f"{args.chat_base_url.rstrip('/')}/api/audio/transcribe", payload, args.timeout)
    print(json.dumps(result, ensure_ascii=False, indent=2))
    if result.get("error"):
        return 1
    return 0 if result.get("model") and result.get("bytes") else 1


def format_url_error(exc: urllib.error.URLError) -> str:
    if isinstance(exc, urllib.error.HTTPError):
        try:
            body = exc.read().decode("utf-8", errors="replace").strip()
        except OSError:
            body = ""
        return f"HTTP {exc.code}: {body or exc.reason}"
    return str(exc)


def main() -> int:
    parser = argparse.ArgumentParser(description="Smoke test audio transcription through the model chat API.")
    parser.add_argument("--chat-base-url", default="http://192.168.220.91:8765")
    parser.add_argument("--audio-base-url", default="http://docker-gpu.cin.su:8020")
    parser.add_argument("--language", default="russian")
    parser.add_argument("--task", default="transcribe")
    parser.add_argument("--seconds", type=float, default=1.0)
    parser.add_argument("--timeout", type=int, default=600)
    parser.add_argument("--allow-unavailable", action="store_true")
    args = parser.parse_args()

    try:
        return run(args)
    except (OSError, ValueError, urllib.error.URLError) as exc:
        message = format_url_error(exc) if isinstance(exc, urllib.error.URLError) else str(exc)
        print(f"Smoke audio transcription failed: {message}", file=sys.stderr)
        return 0 if args.allow_unavailable else 1


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