"""Turn meeting_<lang>/script.json into two overlapping m4a recordings plus a ground-truth timeline.

Steps: TTS every line with Gemini prebuilt voices (cached per line) -> mix on one timeline with room tone ->
phone-quality processing for the dial-in speaker -> five-minute break -> split into two files that overlap.
Usage: build_meeting.py <lang>   (needs GEMINI_API_KEY)
"""
import concurrent.futures as cf, hashlib, json, random, subprocess, sys
from pathlib import Path
import numpy as np, soundfile as sf

sys.path.insert(0, str(Path(__file__).parent))
from gemini_tts import speak  # noqa: E402

LANG = sys.argv[1]
D = Path(__file__).parent / f"meeting_{LANG}"
CFG = json.loads((D / "config.json").read_text(encoding="utf-8"))
SR = 24000
rng = random.Random(7)


def tts_line(i, line):
    voice = CFG["voices"][line["speaker"]]
    key = hashlib.sha1(f"{voice}|{line['text']}".encode()).hexdigest()[:12]
    out = D / "lines" / f"{i:03d}_{line['speaker']}_{key}.wav"
    if not out.exists():
        out.parent.mkdir(exist_ok=True)
        style = CFG.get("style_prefix", "")
        for attempt in range(4):
            try:
                speak(voice, style + line["text"], str(out)); break
            except Exception as e:
                print("retry", i, e, flush=True)
    return out


def phone(x):
    # narrowband, quiet, with line noise: 8 kHz resample + 300-3400 Hz band via sox
    tmp_in, tmp_out = D / "_ph_in.wav", D / "_ph_out.wav"
    sf.write(tmp_in, x, SR)
    subprocess.run(["sox", str(tmp_in), "-r", "8000", str(tmp_out), "sinc", "300-3400", "vol", str(CFG["phone_gain"])], check=True,
                   stderr=subprocess.DEVNULL)
    y, sr = sf.read(tmp_out)
    y = np.interp(np.arange(0, len(y), sr / SR), np.arange(len(y)), y)
    return y + np.random.default_rng(1).normal(0, CFG["phone_noise"], len(y))


def main():
    script = json.loads((D / "script.json").read_text(encoding="utf-8"))
    speech = [(i, l) for i, l in enumerate(script) if l["speaker"] != "BREAK"]
    with cf.ThreadPoolExecutor(6) as ex:
        paths = dict(zip([i for i, _ in speech], ex.map(lambda p: tts_line(*p), speech)))
    pieces, timeline, t = [], [], 2.0
    pieces.append(np.zeros(int(2.0 * SR)))
    for i, line in enumerate(script):
        if line["speaker"] == "BREAK":
            dur = CFG["break_seconds"]; pieces.append(np.zeros(int(dur * SR))); t += dur; continue
        x, sr = sf.read(paths[i]); assert sr == SR
        if line["speaker"] == CFG["phone_speaker"]:
            x = phone(x)
        timeline.append({"i": i, "speaker": line["speaker"], "text": line["text"], "start": round(t, 2), "end": round(t + len(x) / SR, 2)})
        pieces.append(x); t += len(x) / SR
        gap = rng.uniform(0.35, 0.9); pieces.append(np.zeros(int(gap * SR))); t += gap
    audio = np.concatenate(pieces)
    audio = audio + np.random.default_rng(2).normal(0, CFG["room_noise"], len(audio))  # room tone everywhere
    total = len(audio) / SR
    # split point: inside a non-phone utterance near the configured fraction
    target = total * CFG["split_fraction"]
    cand = [u for u in timeline if u["speaker"] != CFG["phone_speaker"] and u["start"] > target]
    cut = round((cand[0]["start"] + cand[0]["end"]) / 2, 2)
    p2_start = round(cut - CFG["overlap_seconds"], 2)
    full = D / "full.wav"; sf.write(full, audio, SR)
    pub = D / "recordings"; pub.mkdir(exist_ok=True)
    names = CFG["file_names"]
    subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-i", str(full), "-t", str(cut), "-c:a", "aac", "-b:a", "64k", str(pub / names[0])], check=True)
    subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-ss", str(p2_start), "-i", str(full), "-af", "volume=0.8", "-c:a", "aac", "-b:a", "64k", str(pub / names[1])], check=True)
    truth = {"total_seconds": round(total, 2), "part1_end": cut, "part2_start": p2_start, "phone_speaker": CFG["phone_speaker"], "utterances": timeline}
    (D / "truth.json").write_text(json.dumps(truth, ensure_ascii=False, indent=1), encoding="utf-8")
    print(json.dumps({k: v for k, v in truth.items() if k != "utterances"}), len(timeline), "utterances")


if __name__ == "__main__":
    main()
