from __future__ import annotations

import argparse
import json
import os
import pathlib
import signal
import time


def atomic_json(path: pathlib.Path | None, value: dict[str, object]) -> None:
    if path is None:
        return
    path.parent.mkdir(parents=True, exist_ok=True)
    temporary = path.with_suffix(path.suffix + ".tmp")
    temporary.write_text(
        json.dumps(value, ensure_ascii=False, sort_keys=True) + "\n",
        encoding="utf-8",
        newline="\n",
    )
    os.replace(temporary, path)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--ready-path", type=pathlib.Path)
    parser.add_argument("--metrics-path", type=pathlib.Path)
    parser.add_argument("--stop-path", type=pathlib.Path)
    args = parser.parse_args()

    stop_requested = False

    def request_stop(_signum: int, _frame: object) -> None:
        nonlocal stop_requested
        stop_requested = True

    for name in ("SIGTERM", "SIGINT"):
        item = getattr(signal, name, None)
        if item is not None:
            signal.signal(item, request_stop)

    started_epoch = time.time()
    started = time.perf_counter()
    busy_seconds = 0.0
    cycle_count = 0
    atomic_json(args.ready_path, {
        "ready": True,
        "pid": os.getpid(),
        "level": "cpu-medium",
        "target_busy_fraction": 0.50,
        "started_epoch": started_epoch,
    })

    def stopping() -> bool:
        return stop_requested or (args.stop_path is not None and args.stop_path.is_file())

    while not stopping():
        busy_started = time.perf_counter()
        busy_deadline = busy_started + 0.05
        value = 1
        while time.perf_counter() < busy_deadline and not stopping():
            value = (value * 1103515245 + 12345) & 0x7FFFFFFF
        busy_seconds += max(0.0, time.perf_counter() - busy_started)
        cycle_count += 1
        elapsed = max(time.perf_counter() - started, 1e-9)
        atomic_json(args.metrics_path, {
            "pid": os.getpid(),
            "cycle_count": cycle_count,
            "busy_seconds": busy_seconds,
            "elapsed_seconds": elapsed,
            "observed_busy_fraction": busy_seconds / elapsed,
            "heartbeat_epoch": time.time(),
            "finalized": False,
        })
        if not stopping():
            time.sleep(0.05)

    elapsed = max(time.perf_counter() - started, 1e-9)
    atomic_json(args.metrics_path, {
        "pid": os.getpid(),
        "cycle_count": cycle_count,
        "busy_seconds": busy_seconds,
        "elapsed_seconds": elapsed,
        "observed_busy_fraction": busy_seconds / elapsed,
        "heartbeat_epoch": time.time(),
        "ended_epoch": time.time(),
        "finalized": True,
    })
    return 0


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