#!/usr/bin/env python3
from __future__ import annotations

import json
import sys
from pathlib import Path
import yaml

ROOT = Path(__file__).resolve().parent.parent

def main() -> int:
    graph_path = ROOT / "spec" / "routing" / "decision_graph.yaml"
    if not graph_path.exists():
        print(f"Decision graph spec missing: {graph_path}")
        return 1

    try:
        graph_data = yaml.safe_load(graph_path.read_text(encoding="utf-8")) or {}
    except Exception as e:
        print(f"Failed to parse decision graph: {e}")
        return 1

    nodes = graph_data.get("nodes", [])
    edges = graph_data.get("edges", [])

    # Build adjacency list
    adj = {}
    for node in nodes:
        nid = node.get("id")
        adj[nid] = []

    for edge in edges:
        if len(edge) == 2:
            u, v = edge[0], edge[1]
            if u in adj and v in adj:
                adj[u].append(v)
            else:
                # If nodes are not declared, dynamically add them
                if u not in adj:
                    adj[u] = []
                if v not in adj:
                    adj[v] = []
                adj[u].append(v)

    errors = []
    # Check topological sort order
    in_degree = {n: 0 for n in adj}
    for u in adj:
        for v in adj[u]:
            in_degree[v] += 1

    # Find nodes with 0 in-degree
    queue = [n for n in adj if in_degree[n] == 0]
    topo_order = []
    while queue:
        curr = queue.pop(0)
        topo_order.append(curr)
        for v in adj.get(curr, []):
            in_degree[v] -= 1
            if in_degree[v] == 0:
                queue.append(v)

    # If topological sort is not successful (has cycle), fail
    if len(topo_order) != len(adj):
        errors.append("Decision graph contains a cycle")
        gate_passed = False
    else:
        anti_chase_idx = -1
        if "anti_chase" in topo_order:
            anti_chase_idx = topo_order.index("anti_chase")
        else:
            errors.append("anti_chase node not found in graph")

        target_nodes = ["regime", "sector_beta", "style", "sizing", "execution"]
        if anti_chase_idx != -1:
            for t in target_nodes:
                if t in topo_order:
                    t_idx = topo_order.index(t)
                    if anti_chase_idx >= t_idx:
                        errors.append(f"anti_chase (index {anti_chase_idx}) does not precede {t} (index {t_idx})")
                else:
                    # Missing target node is a failure
                    errors.append(f"Target node {t} not found in topological order")

        gate_passed = len(errors) == 0

    result = {
        "formula_id": "DECISION_GRAPH_PRECEDENCE_VALIDATOR_V1",
        "topo_order": topo_order,
        "errors": errors,
        "gate": "PASS" if gate_passed else "FAIL"
    }

    # Write output to Temp
    out_dir = ROOT / "Temp"
    out_dir.mkdir(parents=True, exist_ok=True)
    out_path = out_dir / "decision_graph_precedence_validation_v1.json"
    out_path.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")

    print(json.dumps(result, ensure_ascii=True, indent=2))
    return 0 if gate_passed else 1

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