from pathlib import Path
import hashlib
import json
import os
import subprocess
import urllib.request
import urllib.parse
import wave

ROOT = Path(__file__).resolve().parents[1]
BASE = "http://192.168.40.33:7862"
VOICE = "ngoc-huyen-vbee"
spoken = (ROOT / "story/spoken-narration.txt").read_text()
import subprocess
validator = subprocess.run(["python3", "/home/hermes/.hermes/skills/audio-production/gac-mai-audio/scripts/validate_tts_text_contract.py", "--project-root", str(ROOT)], check=True, capture_output=True, text=True)
lineage = json.loads((ROOT / "log/tts-pronunciation.json").read_text())
preflight = {"family_lock_sha256": json.loads((ROOT / "script/story-brief.json").read_text())["family_lock_sha256"], "spoken_sha256": lineage["spoken_narration_sha256"]}
family_hash = preflight["family_lock_sha256"]
segments = [spoken[i:i+2990] for i in range(0, len(spoken), 2990)]
plan_hash = hashlib.sha256((preflight["spoken_sha256"] + json.dumps([hashlib.sha256(x.encode()).hexdigest() for x in segments])).encode()).hexdigest()
state_path = ROOT / "log/tts-state.json"
out_dir = ROOT / "audio/segments"
out_dir.mkdir(parents=True, exist_ok=True)
state = json.loads(state_path.read_text()) if state_path.exists() else {}
if state.get("plan_hash") != plan_hash or state.get("input_sha256") != preflight["spoken_sha256"]:
    state = {"plan_hash": plan_hash, "input_sha256": preflight["spoken_sha256"], "segments": {}}

def sha(path):
    h = hashlib.sha256()
    with path.open("rb") as f:
        for block in iter(lambda: f.read(1024 * 1024), b""):
            h.update(block)
    return h.hexdigest()

for i, text in enumerate(segments):
    key = str(i + 1)
    target = out_dir / f"segment-{i+1:02d}.wav"
    old = state.get("segments", {}).get(key)
    if old and target.exists() and old.get("sha256") == sha(target) and old.get("input_sha256") == hashlib.sha256(text.encode()).hexdigest():
        continue
    payload = urllib.parse.urlencode({"text": text, "voice": VOICE}).encode()
    with urllib.request.urlopen(urllib.request.Request(BASE + "/tts", data=payload, method="POST"), timeout=300) as r:
        part = target.with_suffix(".wav.part")
        part.write_bytes(r.read())
    os.replace(part, target)
    state.setdefault("segments", {})[key] = {"sha256": sha(target), "input_sha256": hashlib.sha256(text.encode()).hexdigest(), "bytes": target.stat().st_size, "family_lock_sha256": family_hash}
    state_path.write_text(json.dumps(state, ensure_ascii=False, indent=2) + "\n")

concat = ROOT / "audio/segments.txt"
concat.write_text("\n".join(f"file '{p.as_posix()}'" for p in sorted(out_dir.glob("segment-*.wav"))) + "\n")
full = ROOT / "audio/story-full.wav"
subprocess.run(["ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", str(concat), "-c", "copy", str(full)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
probe = subprocess.check_output(["ffprobe", "-v", "error", "-show_streams", "-show_format", "-of", "json", str(full)], text=True)
receipt = {"status": "completed", "verified": True, "provider": "piper-wrapper", "base_url": BASE, "endpoint": "/tts", "voice": VOICE, "family_lock_sha256": family_hash, "input_text_sha256": preflight["spoken_sha256"], "segment_count": len(segments), "output_path": str(full), "artifact_sha256": sha(full), "artifact_bytes": full.stat().st_size, "probe": json.loads(probe)}
(ROOT / "log/tts.json").write_text(json.dumps(receipt, ensure_ascii=False, indent=2) + "\n")
print(json.dumps(receipt, ensure_ascii=False))