use super::common::cli::run_br;
use super::{create_issue, init_workspace, normalize_json};
use insta::{assert_json_snapshot, assert_snapshot};
use serde_json::Value;
use std::fs;

// Representative fixture for exact list/show JSON goldens.
//
// Golden update workflow:
// INSTA_UPDATE=always rch exec -- cargo test --test snapshots representative_json_golden
//
// Review the resulting tests/snapshots/snapshots/*.snap diffs before committing.
// The fixture uses fixed IDs, actors, and timestamps, so these snapshots should
// not require masking; they intentionally lock down JSON field order and
// optional/null omission behavior from the CLI serializer.
const LIST_SHOW_JSONL_FIXTURE: &str = r#"{"id":"bd-golden-parent","title":"01 Parent Epic","description":"Parent description","status":"open","priority":1,"issue_type":"epic","assignee":"alice","owner":"owner@example.com","created_at":"2026-01-01T00:00:00Z","created_by":"fixture","updated_at":"2026-01-01T00:00:00Z","due_at":"2026-07-01T00:00:00Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["ops","ux"]}
{"id":"bd-golden-child","title":"02 Child Task","description":"Child description","design":"Design notes","acceptance_criteria":"Acceptance text","notes":"Operator notes","status":"in_progress","priority":2,"issue_type":"task","assignee":"bob","owner":"child@example.com","created_at":"2026-01-02T00:00:00Z","created_by":"fixture","updated_at":"2026-01-02T01:00:00Z","defer_until":"2026-07-03T00:00:00Z","source_repo":".","compaction_level":0,"original_size":0,"labels":["backend"],"dependencies":[{"issue_id":"bd-golden-child","depends_on_id":"bd-golden-parent","type":"parent-child","created_at":"2026-01-02T00:00:00Z","created_by":"fixture","metadata":"{}","thread_id":""}],"comments":[{"id":1,"issue_id":"bd-golden-child","author":"fixture","text":"first comment","created_at":"2026-01-02T02:00:00Z"}]}
{"id":"bd-golden-closed","title":"03 Closed Bug","description":"Closed bug description","status":"closed","priority":0,"issue_type":"bug","assignee":"carol","owner":"owner@example.com","created_at":"2026-01-03T00:00:00Z","created_by":"fixture","updated_at":"2026-01-03T03:00:00Z","closed_at":"2026-01-03T03:00:00Z","close_reason":"fixed","closed_by_session":"session-1","source_repo":".","compaction_level":0,"original_size":0,"labels":["bugfix"]}
{"id":"bd-golden-deleted","title":"04 Deleted Cleanup","status":"tombstone","priority":3,"issue_type":"task","created_at":"2026-01-04T00:00:00Z","created_by":"fixture","updated_at":"2026-01-04T04:00:00Z","deleted_at":"2026-01-04T04:00:00Z","deleted_by":"fixture","delete_reason":"fixture tombstone","original_type":"task","source_repo":".","compaction_level":0,"original_size":0}
"#;

fn init_list_show_golden_workspace() -> super::common::cli::BrWorkspace {
    let workspace = init_workspace();
    let jsonl_path = workspace.root.join(".beads/issues.jsonl");
    fs::write(jsonl_path, LIST_SHOW_JSONL_FIXTURE).expect("write list/show JSONL fixture");

    let import = run_br(
        &workspace,
        ["sync", "--import-only", "--json"],
        "representative_json_golden_import",
    );
    assert!(
        import.status.success(),
        "fixture import failed:\nstdout:\n{}\nstderr:\n{}",
        import.stdout,
        import.stderr
    );

    workspace
}

#[test]
fn snapshot_list_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Issue one", "create_one");
    create_issue(&workspace, "Issue two", "create_two");

    let output = run_br(&workspace, ["list", "--json"], "list_json");
    assert!(
        output.status.success(),
        "list json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("list_json_output", normalize_json(&json));
}

#[test]
fn snapshot_show_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Detailed issue", "create_detail");

    let output = run_br(&workspace, ["show", &id, "--json"], "show_json");
    assert!(
        output.status.success(),
        "show json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("show_json_output", normalize_json(&json));
}

#[test]
fn representative_json_golden_list_output() {
    let workspace = init_list_show_golden_workspace();

    let output = run_br(
        &workspace,
        ["list", "--all", "--sort", "title", "--json"],
        "representative_json_golden_list",
    );
    assert!(
        output.status.success(),
        "representative list JSON failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse list JSON");
    assert_eq!(
        json.get("total").and_then(Value::as_u64),
        Some(3),
        "list --all should include open/in_progress/closed and exclude tombstones"
    );
    assert_snapshot!("representative_list_json_output", output.stdout.trim_end());
}

#[test]
fn representative_json_golden_show_output() {
    let workspace = init_list_show_golden_workspace();

    let output = run_br(
        &workspace,
        [
            "show",
            "bd-golden-parent",
            "bd-golden-child",
            "bd-golden-closed",
            "bd-golden-deleted",
            "--json",
        ],
        "representative_json_golden_show",
    );
    assert!(
        output.status.success(),
        "representative show JSON failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse show JSON");
    assert_eq!(
        json.as_array().map(Vec::len),
        Some(4),
        "show should preserve all requested fixture issues, including tombstones"
    );
    assert_snapshot!("representative_show_json_output", output.stdout.trim_end());
}

#[test]
fn snapshot_ready_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Ready issue", "create_ready");

    let output = run_br(&workspace, ["ready", "--json"], "ready_json");
    assert!(
        output.status.success(),
        "ready json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("ready_json_output", normalize_json(&json));
}

#[test]
#[allow(clippy::similar_names)]
fn snapshot_blocked_json() {
    let workspace = init_workspace();

    // Create a dependency chain
    let blocker = create_issue(&workspace, "Blocker issue", "create_blocker_json");
    let blocked = create_issue(&workspace, "Blocked issue", "create_blocked_json");

    let _ = run_br(
        &workspace,
        ["dep", "add", &blocked, &blocker],
        "dep_add_json",
    );

    let output = run_br(&workspace, ["blocked", "--json"], "blocked_json");
    assert!(
        output.status.success(),
        "blocked json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("blocked_json_output", normalize_json(&json));
}

#[test]
fn snapshot_list_with_filters_json() {
    let workspace = init_workspace();
    let id1 = create_issue(&workspace, "Bug: Fix login", "create_bug_json");
    let id2 = create_issue(&workspace, "Feature: Add theme", "create_feature_json");

    // Update types
    let _ = run_br(
        &workspace,
        ["update", &id1, "--type", "bug"],
        "update_bug_json",
    );
    let _ = run_br(
        &workspace,
        ["update", &id2, "--type", "feature"],
        "update_feature_json",
    );

    // List only bugs
    let output = run_br(
        &workspace,
        ["list", "--type", "bug", "--json"],
        "list_bugs_json",
    );
    assert!(
        output.status.success(),
        "list bugs json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("list_filtered_json_output", normalize_json(&json));
}

#[test]
fn snapshot_stats_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Stats Issue", "create_stats");

    let output = run_br(&workspace, ["stats", "--json"], "stats_json");
    assert!(output.status.success());
    // Parse the JSON string into Value before passing to normalize_json
    let json: serde_json::Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("stats_json_output", normalize_json(&json));
}

#[test]
fn snapshot_create_json() {
    let workspace = init_workspace();

    let output = run_br(
        &workspace,
        [
            "create",
            "New feature request",
            "--type",
            "feature",
            "--priority",
            "1",
            "--json",
        ],
        "create_json",
    );
    assert!(
        output.status.success(),
        "create json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("create_json_output", normalize_json(&json));
}

#[test]
fn snapshot_update_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Issue to update", "create_update");

    let output = run_br(
        &workspace,
        ["update", &id, "--status", "in_progress", "--json"],
        "update_json",
    );
    assert!(
        output.status.success(),
        "update json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("update_json_output", normalize_json(&json));
}

#[test]
fn snapshot_close_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Issue to close", "create_close_json");

    let output = run_br(
        &workspace,
        ["close", &id, "--reason", "Done", "--json"],
        "close_json",
    );
    assert!(
        output.status.success(),
        "close json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("close_json_output", normalize_json(&json));
}

#[test]
fn snapshot_dep_list_json() {
    let workspace = init_workspace();
    let id1 = create_issue(&workspace, "Parent issue", "create_parent");
    let id2 = create_issue(&workspace, "Child issue", "create_child");

    // Add dependency
    let add = run_br(&workspace, ["dep", "add", &id2, &id1], "dep_add");
    assert!(add.status.success(), "dep add failed: {}", add.stderr);

    let output = run_br(&workspace, ["dep", "list", &id2, "--json"], "dep_list_json");
    assert!(
        output.status.success(),
        "dep list json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("dep_list_json_output", normalize_json(&json));
}

#[test]
fn snapshot_search_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Search target", "create_search_target");
    create_issue(&workspace, "Other issue", "create_search_other");

    let output = run_br(&workspace, ["search", "target", "--json"], "search_json");
    assert!(
        output.status.success(),
        "search json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("search_json_output", normalize_json(&json));
}

#[test]
fn snapshot_count_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Count one", "create_count_one");
    create_issue(&workspace, "Count two", "create_count_two");

    let output = run_br(&workspace, ["count", "--json"], "count_json");
    assert!(
        output.status.success(),
        "count json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("count_json_output", normalize_json(&json));
}

#[test]
fn snapshot_count_grouped_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Grouped one", "create_grouped_one");
    let _ = run_br(
        &workspace,
        ["update", &id, "--status", "in_progress"],
        "update_grouped_one",
    );
    create_issue(&workspace, "Grouped two", "create_grouped_two");

    let output = run_br(
        &workspace,
        ["count", "--by", "status", "--json"],
        "count_grouped_json",
    );
    assert!(
        output.status.success(),
        "count grouped json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("count_grouped_json_output", normalize_json(&json));
}

#[test]
fn snapshot_stale_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Stale issue", "create_stale");

    let output = run_br(&workspace, ["stale", "--days", "0", "--json"], "stale_json");
    assert!(
        output.status.success(),
        "stale json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("stale_json_output", normalize_json(&json));
}

#[test]
fn snapshot_comments_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Commented issue", "create_commented");

    let add = run_br(
        &workspace,
        ["comments", "add", &id, "First comment", "--json"],
        "comments_add_json",
    );
    assert!(
        add.status.success(),
        "comments add json failed: {}",
        add.stderr
    );

    let add_json: Value = serde_json::from_str(&add.stdout).expect("parse json");
    assert_json_snapshot!("comments_add_json_output", normalize_json(&add_json));

    let list = run_br(
        &workspace,
        ["comments", "list", &id, "--json"],
        "comments_list_json",
    );
    assert!(
        list.status.success(),
        "comments list json failed: {}",
        list.stderr
    );

    let list_json: Value = serde_json::from_str(&list.stdout).expect("parse json");
    assert_json_snapshot!("comments_list_json_output", normalize_json(&list_json));
}

#[test]
fn snapshot_label_json() {
    let workspace = init_workspace();
    let id = create_issue(&workspace, "Labeled issue", "create_labeled");

    let add = run_br(
        &workspace,
        ["label", "add", &id, "backend", "--json"],
        "label_add_json",
    );
    assert!(
        add.status.success(),
        "label add json failed: {}",
        add.stderr
    );

    let add_json: Value = serde_json::from_str(&add.stdout).expect("parse json");
    assert_json_snapshot!("label_add_json_output", normalize_json(&add_json));

    let list = run_br(
        &workspace,
        ["label", "list", &id, "--json"],
        "label_list_json",
    );
    assert!(
        list.status.success(),
        "label list json failed: {}",
        list.stderr
    );

    let list_json: Value = serde_json::from_str(&list.stdout).expect("parse json");
    assert_json_snapshot!("label_list_json_output", normalize_json(&list_json));

    let list_all = run_br(
        &workspace,
        ["label", "list-all", "--json"],
        "label_list_all_json",
    );
    assert!(
        list_all.status.success(),
        "label list-all json failed: {}",
        list_all.stderr
    );

    let list_all_json: Value = serde_json::from_str(&list_all.stdout).expect("parse json");
    assert_json_snapshot!("label_list_all_json_output", normalize_json(&list_all_json));
}

#[test]
fn snapshot_orphans_json() {
    let workspace = init_workspace();

    let output = run_br(&workspace, ["orphans", "--json"], "orphans_json");
    assert!(
        output.status.success(),
        "orphans json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("orphans_json_output", normalize_json(&json));
}

#[test]
fn snapshot_graph_json() {
    let workspace = init_workspace();
    let root = create_issue(&workspace, "Graph root", "create_graph_root");
    let child = create_issue(&workspace, "Graph child", "create_graph_child");

    let _ = run_br(
        &workspace,
        ["dep", "add", &child, &root],
        "graph_dep_add_json",
    );

    let output = run_br(&workspace, ["graph", &root, "--json"], "graph_json");
    assert!(
        output.status.success(),
        "graph json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("graph_json_output", normalize_json(&json));
}

// ============================================================================
// Edge Cases: Empty Results
// ============================================================================

#[test]
fn snapshot_list_empty_json() {
    let workspace = init_workspace();

    let output = run_br(&workspace, ["list", "--json"], "list_empty_json");
    assert!(
        output.status.success(),
        "list empty json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("list_empty_json_output", normalize_json(&json));
}

#[test]
fn snapshot_ready_empty_json() {
    let workspace = init_workspace();

    let output = run_br(&workspace, ["ready", "--json"], "ready_empty_json");
    assert!(
        output.status.success(),
        "ready empty json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("ready_empty_json_output", normalize_json(&json));
}

#[test]
fn snapshot_blocked_empty_json() {
    let workspace = init_workspace();

    let output = run_br(&workspace, ["blocked", "--json"], "blocked_empty_json");
    assert!(
        output.status.success(),
        "blocked empty json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("blocked_empty_json_output", normalize_json(&json));
}

#[test]
fn snapshot_search_no_match_json() {
    let workspace = init_workspace();
    create_issue(&workspace, "Existing issue", "create_for_search_miss");

    let output = run_br(
        &workspace,
        ["search", "nonexistent_xyz", "--json"],
        "search_no_match_json",
    );
    assert!(
        output.status.success(),
        "search no match json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("search_no_match_json_output", normalize_json(&json));
}

#[test]
fn snapshot_stale_empty_json() {
    let workspace = init_workspace();

    let output = run_br(
        &workspace,
        ["stale", "--days", "0", "--json"],
        "stale_empty_json",
    );
    assert!(
        output.status.success(),
        "stale empty json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("stale_empty_json_output", normalize_json(&json));
}

#[test]
fn snapshot_count_empty_json() {
    let workspace = init_workspace();

    let output = run_br(&workspace, ["count", "--json"], "count_empty_json");
    assert!(
        output.status.success(),
        "count empty json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("count_empty_json_output", normalize_json(&json));
}

// ============================================================================
// Ordering Guarantees
// ============================================================================

#[test]
fn snapshot_list_priority_ordering_json() {
    let workspace = init_workspace();

    // Create issues with different priorities (lower number = higher priority)
    let id_low = create_issue(&workspace, "Low priority task", "create_low_prio");
    let id_high = create_issue(&workspace, "High priority task", "create_high_prio");
    let id_crit = create_issue(&workspace, "Critical task", "create_crit_prio");

    let _ = run_br(
        &workspace,
        ["update", &id_low, "--priority", "3"],
        "set_low_prio",
    );
    let _ = run_br(
        &workspace,
        ["update", &id_high, "--priority", "1"],
        "set_high_prio",
    );
    let _ = run_br(
        &workspace,
        ["update", &id_crit, "--priority", "0"],
        "set_crit_prio",
    );

    let output = run_br(&workspace, ["list", "--json"], "list_priority_order_json");
    assert!(
        output.status.success(),
        "list priority ordering json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    let normalized = normalize_json(&json);
    assert_json_snapshot!("list_priority_ordering_json_output", normalized);

    // Also verify ordering programmatically: priorities should be ascending
    if let Value::Array(items) = &json {
        let priorities: Vec<i64> = items
            .iter()
            .filter_map(|item| item.get("priority").and_then(Value::as_i64))
            .collect();
        for window in priorities.windows(2) {
            assert!(
                window[0] <= window[1],
                "list ordering violated: P{} should come before P{}",
                window[0],
                window[1]
            );
        }
    }
}

#[test]
fn snapshot_ready_priority_ordering_json() {
    let workspace = init_workspace();

    // Create multiple ready issues with different priorities
    let id_p3 = create_issue(&workspace, "Backlog ready task", "create_ready_p3");
    let id_p1 = create_issue(&workspace, "Urgent ready task", "create_ready_p1");
    let id_p2 = create_issue(&workspace, "Normal ready task", "create_ready_p2");

    let _ = run_br(
        &workspace,
        ["update", &id_p3, "--priority", "3"],
        "set_ready_p3",
    );
    let _ = run_br(
        &workspace,
        ["update", &id_p1, "--priority", "1"],
        "set_ready_p1",
    );
    let _ = run_br(
        &workspace,
        ["update", &id_p2, "--priority", "2"],
        "set_ready_p2",
    );

    let output = run_br(&workspace, ["ready", "--json"], "ready_priority_order_json");
    assert!(
        output.status.success(),
        "ready priority ordering json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    let normalized = normalize_json(&json);
    assert_json_snapshot!("ready_priority_ordering_json_output", normalized);

    // Ready uses hybrid sort: P0/P1 first, then others by created_at ASC.
    // The snapshot locks down the exact ordering. Verify P0/P1 appear before P2+.
    if let Value::Array(items) = &json {
        let priorities: Vec<i64> = items
            .iter()
            .filter_map(|item| item.get("priority").and_then(Value::as_i64))
            .collect();
        let high_prio_end = priorities
            .iter()
            .position(|&p| p > 1)
            .unwrap_or(priorities.len());
        for &p in &priorities[..high_prio_end] {
            assert!(p <= 1, "P0/P1 should appear in the first group, got P{p}");
        }
        for &p in &priorities[high_prio_end..] {
            assert!(p > 1, "P2+ should appear in the second group, got P{p}");
        }
    }
}

// ============================================================================
// Multiple IDs / Complex Scenarios
// ============================================================================

#[test]
fn snapshot_show_multiple_ids_json() {
    let workspace = init_workspace();
    let id1 = create_issue(&workspace, "First detailed issue", "create_multi_1");
    let id2 = create_issue(&workspace, "Second detailed issue", "create_multi_2");

    let output = run_br(
        &workspace,
        ["show", &id1, &id2, "--json"],
        "show_multi_json",
    );
    assert!(
        output.status.success(),
        "show multiple ids json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    let normalized = normalize_json(&json);
    assert_json_snapshot!("show_multiple_ids_json_output", normalized);

    // Verify we got exactly 2 results
    if let Value::Array(items) = &json {
        assert_eq!(items.len(), 2, "show with 2 IDs should return 2 results");
    }
}

#[test]
fn snapshot_count_grouped_by_type_json() {
    let workspace = init_workspace();
    let id1 = create_issue(&workspace, "Bug to fix", "create_typed_bug");
    let id2 = create_issue(&workspace, "Feature to add", "create_typed_feature");
    create_issue(&workspace, "Plain task", "create_typed_task");

    let _ = run_br(
        &workspace,
        ["update", &id1, "--type", "bug"],
        "set_type_bug",
    );
    let _ = run_br(
        &workspace,
        ["update", &id2, "--type", "feature"],
        "set_type_feature",
    );

    let output = run_br(
        &workspace,
        ["count", "--by", "type", "--json"],
        "count_by_type_json",
    );
    assert!(
        output.status.success(),
        "count grouped by type json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("count_grouped_by_type_json_output", normalize_json(&json));
}

#[test]
fn snapshot_count_grouped_by_priority_json() {
    let workspace = init_workspace();
    let id1 = create_issue(&workspace, "Critical item", "create_prio_p0");
    let id2 = create_issue(&workspace, "Normal item", "create_prio_p2");
    create_issue(&workspace, "Default item", "create_prio_default");

    let _ = run_br(
        &workspace,
        ["update", &id1, "--priority", "0"],
        "set_prio_p0",
    );
    let _ = run_br(
        &workspace,
        ["update", &id2, "--priority", "3"],
        "set_prio_p3",
    );

    let output = run_br(
        &workspace,
        ["count", "--by", "priority", "--json"],
        "count_by_priority_json",
    );
    assert!(
        output.status.success(),
        "count grouped by priority json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!(
        "count_grouped_by_priority_json_output",
        normalize_json(&json)
    );
}

#[test]
fn snapshot_graph_all_json() {
    let workspace = init_workspace();
    let root1 = create_issue(&workspace, "Graph root A", "create_graph_root_a");
    let child1 = create_issue(&workspace, "Graph child of A", "create_graph_child_a");
    let root2 = create_issue(&workspace, "Graph root B", "create_graph_root_b");

    let _ = run_br(
        &workspace,
        ["dep", "add", &child1, &root1],
        "graph_all_dep_add",
    );

    // graph --all shows all roots
    let output = run_br(&workspace, ["graph", "--all", "--json"], "graph_all_json");
    assert!(
        output.status.success(),
        "graph all json failed: {}",
        output.stderr
    );

    let json: Value = serde_json::from_str(&output.stdout).expect("parse json");
    assert_json_snapshot!("graph_all_json_output", normalize_json(&json));

    // Suppress unused variable warning
    let _ = root2;
}
