#!/usr/bin/env python3
"""AAE Lab 08: exact, expiring human approval for side-effecting actions."""
from dataclasses import dataclass
from hashlib import sha256
import json

@dataclass(frozen=True)
class Action:
    tool: str
    target: str
    arguments: dict
    risk: str

@dataclass(frozen=True)
class Approval:
    action_fingerprint: str
    approved_by: str
    expires_at: int


def fingerprint(action: Action) -> str:
    payload = {"tool": action.tool, "target": action.target, "arguments": action.arguments}
    return sha256(json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()).hexdigest()

APPROVALS: dict[str, Approval] = {}

def approve(action: Action, approved_by: str, now: int, ttl: int = 10):
    key = fingerprint(action)
    APPROVALS[key] = Approval(key, approved_by, now + ttl)
    print("APPROVED:", action.tool, action.target, f"until t={now + ttl}")


def execute(action: Action, now: int):
    if action.risk == "read":
        return f"READ executed: {action.tool} {action.target}"
    key = fingerprint(action)
    approval = APPROVALS.get(key)
    if approval is None:
        raise PermissionError("matching approval required")
    if now > approval.expires_at:
        raise PermissionError("approval expired")
    return f"CHANGE executed: {action.tool} {action.target} approved_by={approval.approved_by}"

print("AAE Lab 08 — proposal → approval → revalidation → execution\n")
read = Action("get_logs", "prod-web-03", {"lines": 50}, "read")
restart = Action("restart_service", "prod-web-03", {"service": "nginx"}, "change")
changed = Action("restart_service", "prod-web-04", {"service": "nginx"}, "change")
delete = Action("delete_database", "prod-db-01", {"database": "orders"}, "high")

print(execute(read, now=1))

try:
    execute(restart, now=1)
except PermissionError as exc:
    print("PAUSED:", exc)

approve(restart, approved_by="operator@example.com", now=2, ttl=10)
print(execute(restart, now=3))

print("\nChanged target after approval:")
try:
    execute(changed, now=3)
except PermissionError as exc:
    print("✓ Rejected changed request:", exc)
else:
    raise SystemExit("FAIL: changed request reused old approval")

print("\nExpired approval:")
try:
    execute(restart, now=20)
except PermissionError as exc:
    print("✓ Rejected expired approval:", exc)
else:
    raise SystemExit("FAIL: expired approval executed")

print("\nHigh-consequence request remains unapproved:")
try:
    execute(delete, now=3)
except PermissionError as exc:
    print("✓ Rejected high-consequence request:", exc)
else:
    raise SystemExit("FAIL: destructive request executed without approval")
