from __future__ import annotations

import argparse
import hashlib
import json
import os
import pathlib
import platform
import re
import sys
import time


ROOT = pathlib.Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(ROOT / "src"))

from reliability_core.process_control import run_supervised_process
from scripts.build_evidence import normalized_tree_hash


def _sha(path: pathlib.Path) -> str:
    digest=hashlib.sha256()
    with path.open("rb") as stream:
        for block in iter(lambda:stream.read(1024*1024),b""): digest.update(block)
    return digest.hexdigest()


def main() -> int:
    parser=argparse.ArgumentParser()
    parser.add_argument("--output-dir",type=pathlib.Path,required=True)
    parser.add_argument("--run-id",required=True)
    parser.add_argument("--run-ordinal",type=int,required=True)
    parser.add_argument("--source-origin",choices=("candidate","final"),required=True)
    parser.add_argument("--suite-kind",choices=("full","target"),required=True)
    parser.add_argument("--target")
    parser.add_argument("--timeout-seconds",type=float,default=420)
    args=parser.parse_args()
    if args.suite_kind=="target" and not args.target:
        parser.error("--target is required for target runs")
    args.output_dir.mkdir(parents=True,exist_ok=True)
    command=[sys.executable,"run_all.py","--tests-only"] if args.suite_kind=="full" else [sys.executable,"-m","unittest","-v",str(args.target)]
    started_epoch=time.time()
    row=run_supervised_process(command,ROOT,environment={**os.environ,"PYTHONDONTWRITEBYTECODE":"1","EVIDENCE_NESTING_LEVEL":"1"},total_timeout_seconds=args.timeout_seconds,max_output_bytes=8*1024*1024)
    ended_epoch=time.time()
    stdout_path=args.output_dir/f"{args.run_id}.stdout.txt"; stderr_path=args.output_dir/f"{args.run_id}.stderr.txt"
    stdout_path.write_text(row["stdout"],encoding="utf-8"); stderr_path.write_text(row["stderr"],encoding="utf-8")
    text=row["stdout"]+"\n"+row["stderr"]
    counts=re.findall(r"Ran\s+(\d+)\s+tests?",text)
    record={
        "run_id":args.run_id,"platform":sys.platform,"platform_detail":platform.platform(),"python_version":platform.python_version(),
        "source_tree_sha256":normalized_tree_hash(ROOT),"command":command,"started_epoch":started_epoch,"ended_epoch":ended_epoch,
        "exit_code":row["exit_code"],"timed_out":row["timed_out"],"orphan_process_count":row["orphan_process_count"],"zombie_process_count":row["zombie_process_count"],
        "test_count":int(counts[-1]) if counts else 0,"stdout_file":stdout_path.name,"stderr_file":stderr_path.name,"stdout_sha256":_sha(stdout_path),"stderr_sha256":_sha(stderr_path),
        "run_ordinal":args.run_ordinal,"cold_start":True,"source_origin":args.source_origin,"suite_kind":args.suite_kind,"target":args.target,
        "output_drain_threads_stopped":row["output_drain_threads_stopped"],"watchdog_timeout_seconds":args.timeout_seconds,
    }
    target=args.output_dir/f"{args.run_id}.json"; target.write_text(json.dumps(record,sort_keys=True,indent=2),encoding="utf-8")
    print(json.dumps({"record":str(target),"passed":record["exit_code"]==0 and not record["timed_out"] and record["orphan_process_count"]==0 and record["zombie_process_count"]==0,"test_count":record["test_count"]},sort_keys=True))
    return 0 if record["exit_code"]==0 and not record["timed_out"] and record["orphan_process_count"]==0 and record["zombie_process_count"]==0 else 2


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