#![allow(
    clippy::indexing_slicing,
    reason = "unwraps are allowed anywhere in tests"
)]

use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use std::assert_matches;

use super::{Price, Warning};
use crate::{
    json::{self, FromJson as _},
    warning::test::VerdictTestExt as _,
};

#[test]
fn should_create_from_json_with_only_excl_vat_field() {
    const JSON: &str = r#"{
            "excl_vat": 10.2
        }"#;

    let doc = json::parse(JSON.into()).unwrap();
    let price = Price::from_json(doc.root()).unwrap().unwrap();

    assert!(price.incl_vat.is_none());
    assert_eq!(Decimal::from(price.excl_vat), dec!(10.2));
}

#[test]
fn should_create_from_json_with_excl_and_incl_vat_fields() {
    const JSON: &str = r#"{
            "excl_vat": 10.2,
            "incl_vat": 12.3
        }"#;

    let doc = json::parse(JSON.into()).unwrap();
    let price = Price::from_json(doc.root()).unwrap().unwrap();

    assert_eq!(Decimal::from(price.incl_vat.unwrap()), dec!(12.3));
    assert_eq!(Decimal::from(price.excl_vat), dec!(10.2));
}

#[test]
fn should_fail_to_create_from_non_object_json() {
    const JSON: &str = "12.3";

    let doc = json::parse(JSON.into()).unwrap();
    let error = Price::from_json(doc.root()).unwrap_only_error();

    assert_matches!(error.into_warning(), Warning::InvalidType { .. });
}

#[test]
fn should_fail_to_create_from_json_as_excl_vat_is_required() {
    const JSON: &str = r#"{
            "incl_vat": 12.3
        }"#;

    let doc = json::parse(JSON.into()).unwrap();
    let error = Price::from_json(doc.root()).unwrap_only_error();

    assert_matches!(error.into_warning(), Warning::MissingExclVatField);
}

#[test]
fn should_create_from_json_and_warn_about_excl_vat_greater_than_incl_vat() {
    const JSON: &str = r#"{
            "excl_vat": 12.3,
            "incl_vat": 10.2
        }"#;

    let doc = json::parse(JSON.into()).unwrap();
    let (_price, warnings) = Price::from_json(doc.root()).unwrap().into_parts();
    let warnings = warnings.into_path_as_str_map();
    let warnings = &warnings["$"];

    assert_matches!(
        warnings.as_slice(),
        [Warning::ExclusiveVatGreaterThanInclusive]
    );
}
