#!/usr/bin/env python3
"""Deterministic, no-network policy and event validator for Mission 0."""
import argparse
import hashlib
import json
from pathlib import Path
import sys

EXPECTED = {"type": "change_column_value", "columnId": "zoom_action", "action": "Create new link"}

class PolicyDenied(ValueError):
    pass

def normalize(payload):
    event = payload.get("event") or {}
    policy = payload.get("policy") or {}
    required = ["id", "type", "boardId", "pulseId", "columnId", "value"]
    missing = [key for key in required if event.get(key) in (None, "")]
    if missing:
        raise ValueError("missing fields: " + ", ".join(missing))
    if policy.get("data_classification") != "synthetic_training":
        raise PolicyDenied("only the synthetic training data class is allowed in Mission 0")
    if policy.get("recording_authorized") is not True or policy.get("consent_withdrawn") is True:
        raise PolicyDenied("recording authorization is absent or withdrawn")
    retention_days = policy.get("retention_days")
    if not isinstance(retention_days, int) or not 1 <= retention_days <= 30:
        raise PolicyDenied("synthetic retention must be between 1 and 30 days")
    action = (((event.get("value") or {}).get("label") or {}).get("text") or "").strip()
    if event["type"] != EXPECTED["type"] or event["columnId"] != EXPECTED["columnId"] or action != EXPECTED["action"]:
        raise ValueError("unsupported event contract")
    intent = f"monday:{event['boardId']}:{event['pulseId']}:{event['id']}:{action.lower().replace(' ', '_')}"
    key = hashlib.sha256(intent.encode("utf-8")).hexdigest()
    return {
        "validation": "pass",
        "event_id": str(event["id"]),
        "idempotency_key": "sha256:" + key,
        "normalized_event": {
            "source": "monday",
            "board_id": str(event["boardId"]),
            "item_id": str(event["pulseId"]),
            "command": "create_meeting_link",
            "data_classification": policy["data_classification"],
            "recording_authorized": True,
            "retention_days": retention_days,
        },
        "state_transition": {"from": "new", "to": "link_requested"},
        "side_effects_executed": 0,
    }

def load(path):
    return json.loads(Path(path).read_text(encoding="utf-8"))

def evaluate(payload):
    try:
        return normalize(payload), 0
    except PolicyDenied as error:
        event = payload.get("event") or {}
        return {
            "validation": "denied",
            "event_id": str(event.get("id") or "unknown"),
            "reason": str(error),
            "state_transition": {"from": "new", "to": "policy_denied"},
            "side_effects_executed": 0,
        }, 3

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "fixture",
        nargs="?",
        default=str(Path(__file__).with_name("monday_event_fixture.json")),
    )
    parser.add_argument("--self-test", action="store_true")
    args = parser.parse_args()
    payload = load(args.fixture)
    if args.self_test:
        first, first_code = evaluate(payload)
        second, second_code = evaluate(payload)
        if first_code or second_code:
            raise SystemExit("self-test failed: authorized fixture was denied")
        if first != second:
            raise SystemExit("self-test failed: repeated normalization drifted")
        denied_path = Path(__file__).with_name("monday_event_no_consent_fixture.json")
        denied, denied_code = evaluate(load(denied_path))
        if denied_code == 0 or denied.get("side_effects_executed") != 0:
            raise SystemExit("self-test failed: no-consent fixture was not safely denied")
        print(json.dumps({
            "self_test": "pass",
            "stable_idempotency_key": first["idempotency_key"],
            "no_consent_gate": denied,
        }, indent=2))
        return 0
    result, code = evaluate(payload)
    print(json.dumps(result, indent=2))
    return code

if __name__ == "__main__":
    sys.exit(main())
