import argparse, json, math, wave
from pathlib import Path

def split_wav(src, output_dir, seconds):
    if not math.isfinite(seconds) or seconds <= 0:
        raise ValueError("seconds must be finite and positive")
    outdir = Path(output_dir)
    with wave.open(str(src), "rb") as w:
        if w.getnchannels() not in (1,2) or w.getsampwidth() != 2 or w.getcomptype() != "NONE":
            raise ValueError("Demo accepts mono/stereo PCM16 only")
        params = w.getparams()
        chunk = int(seconds * w.getframerate())
        if chunk < 1:
            raise ValueError("Chunk shorter than one frame")
        outdir.mkdir(parents=False, exist_ok=False)
        frame_size = w.getnchannels()*w.getsampwidth()
        manifest, start, index = [], 0, 0
        while start < w.getnframes():
            count = min(chunk, w.getnframes()-start)
            target = outdir / f"part-{index:04d}.wav"
            # Exclusive creation prevents accidental file replacement.
            with target.open("xb") as raw_out:
                with wave.open(raw_out, "wb") as out:
                    out.setparams(params._replace(nframes=0))
                    remaining = count
                    while remaining:
                        data = w.readframes(min(65536, remaining))
                        if not data or len(data)%frame_size:
                            raise ValueError("Truncated or misaligned PCM data")
                        received = len(data)//frame_size
                        out.writeframesraw(data)
                        remaining -= received
            manifest.append({"file":target.name,"start_frame":start,
              "end_frame_exclusive":start+count,"sample_rate_hz":w.getframerate(),
              "start_seconds":start/w.getframerate()})
            start += count
            index += 1
        if not manifest:
            raise ValueError("No PCM frames")
        (outdir/"manifest.json").write_text(json.dumps(manifest, indent=2), encoding="utf-8")
        return manifest

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("input")
    parser.add_argument("new_output_directory")
    parser.add_argument("--seconds", type=float, default=30)
    args = parser.parse_args()
    print(json.dumps(split_wav(args.input,args.new_output_directory,args.seconds),indent=2))
