#!/usr/bin/env python3
"""Sample client-to-RCT clock alignment for client-origin transport probes."""

from __future__ import annotations

import json
import pathlib
import shlex
import subprocess
import sys
import time


def sample_clock_alignment(host: str, ssh_opts_text: str) -> dict:
    """Return a midpoint clock-offset estimate between this client and RCT.

    Inputs: SSH host plus the same SSH option string used by the manual probe.
    Outputs: a JSON-serializable clock alignment record.
    Why: client-origin freshness needs the final capture timestamps translated
    into the client's clock without requiring NTP-level access or sudo.
    """

    ssh_opts = shlex.split(ssh_opts_text)
    remote_code = "import sys,time\nfor _ in sys.stdin:\n    print(time.time_ns(), flush=True)\n"
    proc = subprocess.Popen(
        ["ssh", *ssh_opts, host, "python3 -u -c " + shlex.quote(remote_code)],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.DEVNULL,
        text=True,
    )
    rows: list[tuple[int, int]] = []
    try:
        assert proc.stdin is not None
        assert proc.stdout is not None
        for _ in range(9):
            start = time.time_ns()
            proc.stdin.write("sample\n")
            proc.stdin.flush()
            remote = proc.stdout.readline().strip()
            end = time.time_ns()
            if not remote:
                raise RuntimeError("remote clock sampler stopped before returning data")
            midpoint = (start + end) // 2
            rows.append((end - start, int(remote) - midpoint))
            time.sleep(0.05)
    finally:
        if proc.stdin is not None:
            proc.stdin.close()
        proc.terminate()
        try:
            proc.wait(timeout=2)
        except subprocess.TimeoutExpired:
            proc.kill()

    rows.sort(key=lambda row: row[0])
    best = rows[:5]
    offset = round(sum(row[1] for row in best) / len(best))
    uncertainty = max(row[0] for row in best) // 2
    return {
        "schema": "lesavka.client-rct-clock-alignment.v1",
        "available": True,
        "method": "persistent client-to-capture ssh midpoint",
        "capture_host": host,
        "capture_clock_offset_from_client_ns": offset,
        "clock_uncertainty_ns": uncertainty,
        "clock_uncertainty_ms": uncertainty / 1_000_000.0,
        "samples": len(rows),
    }


def main() -> int:
    """CLI entrypoint for the clock alignment helper."""

    if len(sys.argv) != 4:
        print(
            "usage: client_rct_clock_alignment.py TETHYS_HOST SSH_OPTS OUTPUT_JSON",
            file=sys.stderr,
        )
        return 2
    host, ssh_opts_text, output_path = sys.argv[1:]
    data = sample_clock_alignment(host, ssh_opts_text)
    pathlib.Path(output_path).write_text(json.dumps(data, indent=2, sort_keys=True) + "\n")
    offset = data["capture_clock_offset_from_client_ns"] / 1_000_000.0
    uncertainty = data["clock_uncertainty_ms"]
    print(f"   ↪ tethys_from_client_offset_ms={offset:+.3f}")
    print(f"   ↪ clock_alignment_uncertainty_ms={uncertainty:.3f}")
    return 0


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