#!/usr/bin/env python3
"""Synthetic final-state checker self-test, not an Odoo or AI benchmark.

Run in this directory: python3 state-oracle.py
The JSON observations are deliberately constructed fixtures. No network, Odoo,
language model, mail server or production database is used. Normalized keys are
an example observation contract, not an Odoo API payload.
"""
import argparse
import json
from collections import Counter
from pathlib import Path


def inspect_state(state):
    """Check only the deliberately small, complete fixture projection."""
    if not isinstance(state, dict):
        return False
    if set(state) != {"opportunities", "activities", "outbound_events"}:
        return False
    if not isinstance(state["opportunities"], dict):
        return False
    if not isinstance(state["activities"], list) or not isinstance(state["outbound_events"], list):
        return False
    return all(isinstance(row, dict) and "id" in row for row in state["activities"])


def grade(contract, before, observation):
    """Return PASS, FAIL or UNKNOWN for the declared projection only."""
    after = observation.get("final_state")
    if observation.get("snapshot_complete") is not True or not inspect_state(before) or not inspect_state(after):
        return {"status": "UNKNOWN", "reasons": ["complete final observation unavailable"]}

    reasons = []
    if after["opportunities"] != before["opportunities"]:
        reasons.append("opportunity projection changed")
    if after["outbound_events"] != before["outbound_events"]:
        reasons.append("outbound-event projection changed")

    old_ids = [row["id"] for row in before["activities"]]
    final_ids = [row["id"] for row in after["activities"]]
    if len(old_ids) != len(set(old_ids)):
        return {"status": "UNKNOWN", "reasons": ["baseline activity IDs are not unique"]}
    if len(final_ids) != len(set(final_ids)):
        reasons.append("final activity IDs are not unique")
    old = {row["id"]: row for row in before["activities"]}
    final = {row["id"]: row for row in after["activities"]}
    if any(final.get(key) != value for key, value in old.items()):
        reasons.append("existing activity projection changed or disappeared")
    added = [row for row in after["activities"] if row["id"] not in old]

    if contract["action"] == "clarify":
        if added:
            reasons.append("activity created before ambiguity was resolved")
        expected = {"kind": "needs_clarification", "field": contract["clarification_field"]}
        if observation.get("reviewed_disposition") != expected:
            reasons.append("required clarification evidence absent")
    elif contract["action"] == "create_activity":
        if len(added) != 1:
            reasons.append(f"expected one new activity, observed {len(added)}")
        for row in added:
            for field, value in contract["expected_activity"].items():
                if row.get(field) != value:
                    reasons.append(f"new activity {field} differs")
            linked = after["opportunities"].get(row.get("record_ref"), {})
            if linked.get("company") != contract["company"]:
                reasons.append("linked opportunity company differs")
    else:
        return {"status": "UNKNOWN", "reasons": ["unsupported fixture contract"]}

    return {"status": "FAIL" if reasons else "PASS", "reasons": reasons}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("fixtures", nargs="?", type=Path, default=Path(__file__).with_name("state-cases.json"))
    args = parser.parse_args()
    data = json.loads(args.fixtures.read_text())
    results = []
    for case in data["cases"]:
        actual = grade(data["contracts"][case["contract"]], data["baseline"], case["observation"])
        results.append({"id": case["id"], "label": case["label"], "expected": case["expected"],
                        "observed": actual["status"], "matches_expected": actual["status"] == case["expected"],
                        "reasons": actual["reasons"]})
    output = {"evidence_type": "executed Python fixture-validator self-test",
              "not_measured": ["Odoo execution", "AI task success", "tool permissions", "mail delivery", "model variability"],
              "case_count": len(results), "classification_counts": dict(Counter(row["observed"] for row in results)),
              "all_expected_classifications_match": all(row["matches_expected"] for row in results), "results": results}
    print(json.dumps(output, indent=2))
    raise SystemExit(0 if output["all_expected_classifications_match"] else 1)


if __name__ == "__main__":
    main()
