#!/usr/bin/env python3
"""Generate tones or decode AAC through PipeWire's PulseAudio service."""

import argparse
import pathlib
import time

import gi

gi.require_version("Gst", "1.0")
from gi.repository import Gst  # noqa: E402


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("mode", choices=("tone", "aac"))
    parser.add_argument("--rate", type=int, choices=(44100, 48000), required=True)
    parser.add_argument("--seconds", type=int, required=True)
    parser.add_argument("--input")
    args = parser.parse_args()
    if args.seconds <= 0:
        parser.error("--seconds must be positive")

    Gst.init(None)
    if args.mode == "tone":
        pipeline = Gst.parse_launch(
            f"audiotestsrc is-live=true wave=sine freq=997 volume=0.10 ! "
            f"audio/x-raw,format=S16LE,rate={args.rate},channels=2 ! pulsesink"
        )
    else:
        if not args.input or not pathlib.Path(args.input).is_file():
            parser.error("--input must name a readable AAC file")
        pipeline = Gst.ElementFactory.make("playbin")
        sink = Gst.parse_bin_from_description(
            f"audioconvert ! audioresample ! "
            f"audio/x-raw,format=S16LE,rate={args.rate},channels=2 ! pulsesink",
            True,
        )
        pipeline.set_property("audio-sink", sink)
        pipeline.set_property("video-sink", Gst.ElementFactory.make("fakesink"))
        pipeline.set_property("uri", pathlib.Path(args.input).resolve().as_uri())

    bus = pipeline.get_bus()
    deadline = time.monotonic() + args.seconds
    pipeline.set_state(Gst.State.PLAYING)
    try:
        while time.monotonic() < deadline:
            message = bus.timed_pop_filtered(
                200 * Gst.MSECOND,
                Gst.MessageType.ERROR | Gst.MessageType.EOS,
            )
            if message is None:
                continue
            if message.type == Gst.MessageType.ERROR:
                error, debug = message.parse_error()
                raise RuntimeError(f"GStreamer audio failure: {error}: {debug}")
            if args.mode == "aac":
                if not pipeline.seek_simple(
                    Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.KEY_UNIT, 0
                ):
                    raise RuntimeError("Could not loop AAC input for the requested duration")
            else:
                raise RuntimeError("Tone pipeline ended unexpectedly")
    finally:
        pipeline.set_state(Gst.State.NULL)
    return 0


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