from __future__ import annotations

import hashlib
import json
import os
from pathlib import Path

import pytest

from nutricoach_continuity.observer_systemd import SystemdObserverControl


def row(previous: str, status: str, namespace: str, *, timer: bool = False) -> bytes:
    body: dict[str, str | list[str]] = {
        "failures": [] if status == "PASS" else ["first_day_status"],
        "namespace": namespace,
        "previous_row_digest": previous,
        "status": status,
    }
    if timer:
        body["timer_invocation_id"] = "natural-invocation-1"
    raw = json.dumps(body, sort_keys=True, separators=(",", ":")).encode()
    return (
        json.dumps(
            {**body, "row_digest": hashlib.sha256(raw).hexdigest()},
            sort_keys=True,
            separators=(",", ":"),
        ).encode()
        + b"\n"
    )


def systemd_control(
    root: Path, monkeypatch: pytest.MonkeyPatch
) -> tuple[SystemdObserverControl, Path]:
    baseline = root / "observer-r71" / "observations.jsonl"
    output = root / "observer-r71-continuity-r1" / "observations.jsonl"
    baseline.parent.mkdir(mode=0o700)
    output.parent.mkdir(mode=0o700)
    _ = baseline.write_bytes(row("0" * 64, "FAIL", "observer-r71"))
    shim_dir = root / "bin"
    shim_dir.mkdir(mode=0o700)
    calls = root / "calls"
    shim = shim_dir / "systemctl"
    _ = shim.write_text(
        """#!/usr/bin/env python3
import hashlib,json,os,sys
args=sys.argv[1:]
with open(os.environ['SIM_CALLS'],'a',encoding='utf-8') as log: log.write(' '.join(args)+'\\n')
if 'is-active' in args:
 print('inactive'); raise SystemExit(0)
if 'show' in args:
 print('natural-invocation-1'); raise SystemExit(0)
if args[-1]=='continuity.service' or (args[-1]=='continuity.timer' and 'start' in args):
 prior=json.loads(open(os.environ['SIM_BASELINE'],'rb').read().splitlines()[-1])
 body={'failures':[],'namespace':'observer-r71','previous_row_digest':prior['row_digest'],'status':'PASS'}
else:
 raise SystemExit(0)
raw=json.dumps(body,sort_keys=True,separators=(',',':')).encode()
body['row_digest']=hashlib.sha256(raw).hexdigest()
encoded=json.dumps(body,sort_keys=True,separators=(',',':')).encode()+b'\\n'
with open(os.environ['SIM_BASELINE'],'ab') as stream:
 stream.write(encoded); stream.flush(); os.fsync(stream.fileno())
""",
        encoding="utf-8",
    )
    shim.chmod(0o700)
    monkeypatch.setenv("PATH", f"{shim_dir}:{os.environ['PATH']}")
    monkeypatch.setenv("SIM_CALLS", str(calls))
    monkeypatch.setenv("SIM_BASELINE", str(baseline))
    monkeypatch.setenv("SIM_OUTPUT", str(output))
    return (
        SystemdObserverControl(
            baseline,
            output,
            "continuity.timer",
            "continuity.service",
            5,
        ),
        calls,
    )
