use super::super::fixtures::{make_graph, make_store};

use crate::runtime::xyflow::{ControlledGraph, EdgeChange, NodeChange};
use jellyflow_core::core::{CanvasPoint, EdgeId, EdgeReconnectable, NodeId};
use jellyflow_core::ops::{GraphOp, GraphTransaction};

#[test]
fn controlled_graph_applies_projected_store_patch() {
    let (g0, a, _b, _out_port, _in_port, eid) = make_graph();
    let mut store = make_store(g0.clone());
    let mut controlled = ControlledGraph::new(g0);

    let tx = GraphTransaction::from_ops([
        GraphOp::SetNodePos {
            id: a,
            from: CanvasPoint { x: 0.0, y: 0.0 },
            to: CanvasPoint { x: 123.0, y: 456.0 },
        },
        GraphOp::SetEdgeReconnectable {
            id: eid,
            from: None,
            to: Some(EdgeReconnectable::Bool(false)),
        },
    ]);
    let outcome = store.dispatch_transaction(&tx).expect("dispatch");
    let report = controlled.apply_patch_changes(outcome.patch());

    assert_eq!(report.applied(), 2);
    assert_eq!(report.ignored(), 0);
    let store_json = serde_json::to_value(store.graph()).expect("store json");
    let controlled_json = serde_json::to_value(controlled.graph()).expect("controlled json");
    assert_eq!(store_json, controlled_json);
}

#[test]
fn controlled_graph_preserves_xyflow_ignore_missing_contract() {
    let (g0, _a, _b, _out_port, _in_port, _eid) = make_graph();
    let missing_node = NodeId::new();
    let missing_edge = EdgeId::new();
    let mut controlled = ControlledGraph::new(g0.clone());

    let report = controlled.apply_node_changes(&[
        NodeChange::Position {
            id: missing_node,
            position: CanvasPoint { x: 1.0, y: 2.0 },
        },
        NodeChange::Remove { id: missing_node },
    ]);
    let edge_report = controlled.apply_edge_changes(&[EdgeChange::Remove { id: missing_edge }]);

    assert_eq!(report.applied(), 0);
    assert_eq!(report.ignored(), 2);
    assert_eq!(edge_report.applied(), 0);
    assert_eq!(edge_report.ignored(), 1);
    assert_eq!(
        serde_json::to_value(controlled.graph()).expect("controlled json"),
        serde_json::to_value(&g0).expect("original json"),
    );
}
