"""Verify original process evidence and alter only copies for negative controls."""
import argparse
import hashlib
import json
import os
import subprocess
from pathlib import Path


def compare_response(chio, original, cases, unrelated_key):
    """The original context/key come from owner configuration before invocation."""
    files = ("request.json", "verification-context.json", "response.json", "kernel.pub")
    retained = {name: (original / name).read_bytes() for name in files}
    wrong_key = unrelated_key.read_bytes()
    if wrong_key.strip() == retained["kernel.pub"].strip():
        raise ValueError("negative signer control needs a genuinely different key")
    cases.mkdir(mode=0o700)  # Refuse reuse of an earlier comparison directory.

    def check(name, changes, expected_success):
        directory = cases / name
        directory.mkdir(mode=0o700)
        for filename, data in {**retained, **changes}.items():
            with (directory / filename).open("xb") as output:
                output.write(data)
        command = [str(chio), "receipt", "verify-process-response",
                   "--response", str(directory / "response.json"),
                   "--request", str(directory / "request.json"),
                   "--context", str(directory / "verification-context.json"),
                   "--trusted-kernel-pubkey", str(directory / "kernel.pub"), "--json"]
        result = subprocess.run(command, capture_output=True, timeout=90)
        for filename, data in (("stdout", result.stdout), ("stderr", result.stderr),
                               ("exit", f"{result.returncode}\n".encode())):
            with (directory / filename).open("xb") as output:
                output.write(data)
        if expected_success:
            report = json.loads(result.stdout)
            assert result.returncode == 0 and report["receipt_verified"] and report["response_bound"]
            assert report["unchecked_fields"] == ["execution_nonce_json"]
            print("VERIFY original: signature and exact request/context/output bindings")
        else:
            assert result.returncode != 0, f"{name} was unexpectedly accepted"
            raw_error = result.stderr.decode().strip()
            try:
                error = json.loads(raw_error)["message"]
            except (json.JSONDecodeError, KeyError, TypeError):
                error = raw_error
            assert "binding mismatch" in error or "signature" in error or "signer" in error, error
            print(f"REFUSE {name}: {error}")

    encode = lambda value: (json.dumps(value, allow_nan=False) + "\n").encode()
    check("original", {}, True)
    request = json.loads(retained["request.json"])
    request["operation_key"] += "/substituted"
    check("changed-operation", {"request.json": encode(request)}, False)
    context = json.loads(retained["verification-context.json"])
    context["runtime_id"] += "-substituted"
    check("wrong-runtime", {"verification-context.json": encode(context)}, False)
    response = json.loads(retained["response.json"])
    value = response["output"]["value"]
    assert response["output"]["kind"] == "value" and value["status"] == "sent"
    original_sequence = value["sequence"]
    assert isinstance(original_sequence, str) and original_sequence.isdigit()
    value["sequence"] = "2" if original_sequence == "1" else "1"
    assert value["sequence"] != original_sequence
    check("changed-output", {"response.json": encode(response)}, False)
    check("wrong-signer", {"kernel.pub": wrong_key}, False)
    assert all((original / name).read_bytes() == data for name, data in retained.items())
    digests = {name: hashlib.sha256(data).hexdigest() for name, data in retained.items()}
    with (cases / "original-sha256.json").open("x") as output:
        json.dump(digests, output, indent=2)
        output.write("\n")
    print("RETAIN original inputs unchanged; separate nonce and history claims remain unchecked")


if __name__ == "__main__":
    os.umask(0o077)
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--chio", type=Path, required=True)
    parser.add_argument("--original", type=Path, required=True)
    parser.add_argument("--cases", type=Path, required=True)
    parser.add_argument("--unrelated-key", type=Path, required=True)
    args = parser.parse_args()
    compare_response(args.chio.resolve(strict=True), args.original, args.cases, args.unrelated_key)
