use serde_json::{json, Value};

use crate::request::{AssertionMismatch, AssertionMismatchValue, AssertionOutcome};

pub(crate) fn assertion_results_json(assertions: &[AssertionOutcome]) -> Vec<Value> {
    assertions
        .iter()
        .map(|assertion| {
            json!({
                "assertion": assertion.assertion,
                "status": assertion.status.as_str(),
                "message": assertion.message,
                "mismatch": assertion.mismatch.as_ref().map(assertion_mismatch_json),
            })
        })
        .collect()
}

pub(crate) fn assertion_mismatch_json(mismatch: &AssertionMismatch) -> Value {
    json!({
        "kind": mismatch.kind.as_str(),
        "reason": mismatch.reason.as_str(),
        "target": mismatch.target,
        "path": mismatch.path,
        "actualPath": mismatch.actual_path,
        "comparedPath": mismatch.compared_path,
        "operator": mismatch.operator,
        "actual": assertion_mismatch_value_json(&mismatch.actual),
        "expected": assertion_mismatch_value_json(&mismatch.expected),
    })
}

pub(crate) fn assertion_mismatch_value_json(value: &AssertionMismatchValue) -> Value {
    json!({
        "type": value.value_type,
        "value": value.value,
    })
}

pub(crate) fn with_type(mut value: Value, kind: &str) -> Value {
    if let Value::Object(ref mut map) = value {
        map.insert("type".to_string(), Value::String(kind.to_string()));
    }
    value
}