#!/usr/bin/env python3
"""Prepare a Piper ONNX export for sherpa-onnx mobile inference."""

import argparse
import json
import shutil
from pathlib import Path

import onnx


def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("--model", type=Path, required=True)
    parser.add_argument("--config", type=Path, required=True)
    parser.add_argument("--output-dir", type=Path, required=True)
    args = parser.parse_args()

    config = json.loads(args.config.read_text(encoding="utf-8"))
    output_dir: Path = args.output_dir
    output_dir.mkdir(parents=True, exist_ok=True)
    output_model = output_dir / "aletheia_ru.onnx"
    output_config = output_dir / "aletheia_ru.onnx.json"
    output_tokens = output_dir / "tokens.txt"

    shutil.copy2(args.model, output_model)
    shutil.copy2(args.config, output_config)

    id_map = config["phoneme_id_map"]
    # sherpa-onnx's Piper lexicon maps one Unicode code point to one model ID.
    # Newer Piper configs may also contain English diphthong aliases such as
    # "aɪ". eSpeak emits their component code points, and sherpa rejects the
    # multi-code-point aliases, so only the single-code-point table is mobile-safe.
    token_rows = sorted(
        ((ids[0], symbol) for symbol, ids in id_map.items() if len(symbol) == 1),
        key=lambda row: row[0],
    )
    actual_ids = [row[0] for row in token_rows]
    if len(actual_ids) != len(set(actual_ids)):
        raise RuntimeError("phoneme_id_map contains duplicate token identifiers")
    if not actual_ids or min(actual_ids) < 0 or max(actual_ids) >= config["num_symbols"]:
        raise RuntimeError("phoneme_id_map contains a token outside the model symbol range")
    output_tokens.write_text(
        "".join(f"{symbol} {token_id}\n" for token_id, symbol in token_rows),
        encoding="utf-8",
        newline="\n",
    )

    model = onnx.load(str(output_model))
    metadata = {
        "model_type": "vits",
        "comment": "piper",
        "language": "Russian",
        "voice": config["espeak"]["voice"],
        "has_espeak": "1",
        "n_speakers": str(config["num_speakers"]),
        "sample_rate": str(config["audio"]["sample_rate"]),
    }
    existing = {item.key: item for item in model.metadata_props}
    for key, value in metadata.items():
        if key in existing:
            existing[key].value = value
        else:
            item = model.metadata_props.add()
            item.key = key
            item.value = value
    onnx.save(model, str(output_model))

    print(json.dumps({
        "model": str(output_model),
        "model_bytes": output_model.stat().st_size,
        "tokens": len(token_rows),
        "metadata": metadata,
    }, ensure_ascii=False))


if __name__ == "__main__":
    main()
