#![expect(clippy::unwrap_used)]

use super::{print_field_aliases, print_field_values};
use crate::types::{FieldValue, OutputFormat, StatusTransition};

#[test]
fn print_field_values_json_empty() {
    let values: Vec<FieldValue> = vec![];
    let json = serde_json::to_string_pretty(&values).unwrap();
    assert_eq!(json, "[]");
}

#[test]
fn print_field_values_json_with_transitions() {
    let values = vec![FieldValue {
        name: "NEW".into(),
        sort_key: 0,
        is_active: true,
        can_change_to: Some(vec![
            StatusTransition {
                name: "ASSIGNED".into(),
            },
            StatusTransition {
                name: "RESOLVED".into(),
            },
        ]),
    }];
    let json = serde_json::to_string_pretty(&values).unwrap();
    let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
    assert_eq!(parsed[0]["name"], "NEW");
    assert_eq!(parsed[0]["is_active"], true);
    let transitions = parsed[0]["can_change_to"].as_array().unwrap();
    assert_eq!(transitions.len(), 2);
    assert_eq!(transitions[0]["name"], "ASSIGNED");
}

#[test]
fn print_field_values_json_active_and_inactive() {
    let values = vec![
        FieldValue {
            name: "NEW".into(),
            sort_key: 0,
            is_active: true,
            can_change_to: Some(vec![StatusTransition {
                name: "ASSIGNED".into(),
            }]),
        },
        FieldValue {
            name: "CLOSED".into(),
            sort_key: 1,
            is_active: false,
            can_change_to: None,
        },
    ];
    let json = serde_json::to_string_pretty(&values).unwrap();
    let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
    assert_eq!(parsed[0]["name"], "NEW");
    assert_eq!(parsed[0]["is_active"], true);
    assert_eq!(parsed[1]["name"], "CLOSED");
    assert_eq!(parsed[1]["is_active"], false);
    assert!(parsed[1]["can_change_to"].is_null());
}

#[test]
fn print_field_aliases_json_serialization() {
    let aliases: &[(&str, &str)] = &[("status", "bug_status"), ("severity", "bug_severity")];
    let rows: Vec<super::FieldAliasRow> = aliases
        .iter()
        .map(|&(alias, api_name)| super::FieldAliasRow { alias, api_name })
        .collect();
    let json = serde_json::to_string_pretty(&rows).unwrap();
    let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
    let arr = parsed.as_array().unwrap();
    assert_eq!(arr.len(), 2);
    assert_eq!(arr[0]["alias"], "status");
    assert_eq!(arr[0]["api_name"], "bug_status");
    assert_eq!(arr[1]["alias"], "severity");
    assert_eq!(arr[1]["api_name"], "bug_severity");
}

// ── capture_stdout-based formatter tests ─────────────────────────

#[cfg(unix)]
#[tokio::test]
async fn print_field_values_table_empty_renders_only_headers() {
    let _lock = crate::ENV_LOCK.lock().await;
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_values(&[], OutputFormat::Table);
    })
    .await;
    assert!(output.contains("NAME"));
    assert!(output.contains("ACTIVE"));
    assert!(output.contains("CAN CHANGE TO"));
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_values_json_empty_renders_empty_array() {
    let _lock = crate::ENV_LOCK.lock().await;
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_values(&[], OutputFormat::Json);
    })
    .await;
    let parsed = crate::test_helpers::extract_json(&output);
    assert!(parsed.is_array());
    assert_eq!(parsed.as_array().unwrap().len(), 0);
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_values_table_renders_transitions_and_inactive() {
    let _lock = crate::ENV_LOCK.lock().await;
    let values = vec![
        FieldValue {
            name: "NEW".into(),
            sort_key: 0,
            is_active: true,
            can_change_to: Some(vec![
                StatusTransition {
                    name: "ASSIGNED".into(),
                },
                StatusTransition {
                    name: "RESOLVED".into(),
                },
            ]),
        },
        FieldValue {
            name: "CLOSED".into(),
            sort_key: 1,
            is_active: false,
            can_change_to: None,
        },
    ];
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_values(&values, OutputFormat::Table);
    })
    .await;
    assert!(output.contains("NEW"));
    assert!(output.contains("CLOSED"));
    assert!(output.contains("Yes"));
    assert!(output.contains("No"));
    assert!(output.contains("ASSIGNED, RESOLVED"));
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_values_table_handles_unicode_value_name() {
    let _lock = crate::ENV_LOCK.lock().await;
    let values = vec![FieldValue {
        name: "résolu".into(),
        sort_key: 0,
        is_active: true,
        can_change_to: Some(vec![StatusTransition {
            name: "fermé".into(),
        }]),
    }];
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_values(&values, OutputFormat::Table);
    })
    .await;
    assert!(output.contains("résolu"));
    assert!(output.contains("fermé"));
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_values_json_via_print() {
    let _lock = crate::ENV_LOCK.lock().await;
    let values = vec![FieldValue {
        name: "NEW".into(),
        sort_key: 0,
        is_active: true,
        can_change_to: Some(vec![StatusTransition {
            name: "ASSIGNED".into(),
        }]),
    }];
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_values(&values, OutputFormat::Json);
    })
    .await;
    let parsed = crate::test_helpers::extract_json(&output);
    assert_eq!(parsed[0]["name"], "NEW");
    assert_eq!(parsed[0]["is_active"], true);
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_aliases_table_renders_rows() {
    let _lock = crate::ENV_LOCK.lock().await;
    let aliases: &[(&str, &str)] = &[("status", "bug_status"), ("severity", "bug_severity")];
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_aliases(aliases, OutputFormat::Table);
    })
    .await;
    assert!(output.contains("ALIAS"));
    assert!(output.contains("API FIELD NAME"));
    assert!(output.contains("status"));
    assert!(output.contains("bug_status"));
    assert!(output.contains("severity"));
    assert!(output.contains("bug_severity"));
}

#[cfg(unix)]
#[tokio::test]
async fn print_field_aliases_json_via_print() {
    let _lock = crate::ENV_LOCK.lock().await;
    let aliases: &[(&str, &str)] = &[("status", "bug_status")];
    let ((), output) = crate::test_helpers::capture_stdout(async {
        print_field_aliases(aliases, OutputFormat::Json);
    })
    .await;
    let parsed = crate::test_helpers::extract_json(&output);
    assert_eq!(parsed[0]["alias"], "status");
    assert_eq!(parsed[0]["api_name"], "bug_status");
}
