#!/usr/bin/env python3
"""
Run the three fixtures through state_machine.Task and write a trace plus a
results comparison against expected.json. Local, synthetic, no network.

Usage:
    python3 run_demo.py
"""
import json
import os
import sys

from state_machine import Task

HERE = os.path.dirname(os.path.abspath(__file__))


def available_actions(outcome: dict) -> list:
    """Derive the action set an outcome summary screen would offer,
    directly from the task's own state -- not a separately maintained list.
    """
    actions = []
    ext = outcome["external_state"]
    if ext == "confirmed":
        actions.append("inspect")
        if outcome["reversible"]:
            actions.append("reverse")
    elif ext == "unknown":
        actions.append("wait_and_reconcile")
    elif ext == "canceled":
        actions.append("inspect")
    elif ext == "none":
        actions.append("discard")
        actions.append("resume")
    if outcome["local_state"] != "stopped":
        actions.append("schedule_new_work")
    return actions


def outcome_label(outcome: dict) -> str:
    ext = outcome["external_state"]
    return {
        "confirmed": "Confirmed",
        "canceled": "Canceled",
        "unknown": "Unknown",
        "pending": "Pending",
        "none": "Discardable draft",
    }.get(ext, ext)


def outcome_summary_text(task_id: str, outcome: dict, evidence_note: str) -> str:
    ext = outcome["external_state"]
    if ext == "confirmed":
        return f"This change landed. {evidence_note}" if evidence_note else "This change landed."
    if ext == "unknown":
        return f"We don't know if this landed. {evidence_note}" if evidence_note else "We don't know if this landed."
    if ext == "none":
        return "Nothing was sent anywhere. This draft only exists locally and can be discarded freely."
    if ext == "canceled":
        return f"This was canceled. {evidence_note}" if evidence_note else "This was canceled."
    return evidence_note or "No summary available."


def run_fixture(fixture: dict) -> dict:
    task = Task(
        id=fixture["id"],
        description=fixture["description"],
        next_evidence_step=fixture.get("next_evidence_step", ""),
    )
    approval = fixture.get("initial_approval")
    if approval:
        task.grant_approval(
            version=approval["version"], target=approval["target"], amount=approval.get("amount")
        )

    for step in fixture["steps"]:
        action = step["action"]
        if action == "stop":
            task.stop()
        elif action == "resolve_external":
            task.resolve_external(step["outcome"], step.get("evidence_note", ""))
        elif action == "timeout_tick":
            task.timeout_tick()
        elif action == "mark_reversible":
            task.reversible = step["value"]
            task.history.append(f"reversible flag set to {step['value']}")
        else:
            raise ValueError(f"unknown fixture step action: {action!r}")

    outcome = task.to_dict()
    outcome["outcome_label"] = outcome_label(outcome)
    outcome["outcome_summary"] = outcome_summary_text(task.id, outcome, task.evidence_note)
    outcome["available_actions"] = available_actions(outcome)
    outcome["scenario"] = fixture.get("scenario", "")
    return outcome


def main() -> int:
    fixtures_path = os.path.join(HERE, "fixtures.json")
    expected_path = os.path.join(HERE, "expected.json")
    trace_path = os.path.join(HERE, "trace.json")
    results_path = os.path.join(HERE, "results.json")

    with open(fixtures_path) as f:
        fixtures = json.load(f)
    with open(expected_path) as f:
        expected = json.load(f)

    trace = []
    results = {}
    all_pass = True

    for fixture in fixtures:
        outcome = run_fixture(fixture)
        trace.append(outcome)

        exp = expected.get(fixture["id"], {})
        checks = {}
        for key in ("local_state", "external_state", "reversible", "approval_valid", "outcome_label", "available_actions"):
            checks[key] = {
                "expected": exp.get(key),
                "actual": outcome.get(key),
                "match": exp.get(key) == outcome.get(key),
            }
        row_pass = all(c["match"] for c in checks.values())
        all_pass = all_pass and row_pass
        results[fixture["id"]] = {
            "pass": row_pass,
            "checks": checks,
            "outcome": outcome,
        }

    with open(trace_path, "w") as f:
        json.dump(trace, f, indent=2)
    with open(results_path, "w") as f:
        json.dump({"all_pass": all_pass, "fixtures": results}, f, indent=2)

    print(f"Wrote {trace_path}")
    print(f"Wrote {results_path}")
    print(f"All fixtures matched expected.json: {all_pass}")
    for fid, r in results.items():
        print(f"  {fid}: {'PASS' if r['pass'] else 'FAIL'}")

    return 0 if all_pass else 1


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