use azzurro::{
    DeviceAlarmRequest, DeviceAlarmResponse, HistoricRequest, HistoricResponse, RequiredValues,
    RealtimeRequest, RealtimeResponse,
};

// ---------------------------------------------------------------------------
// RequiredValues
// ---------------------------------------------------------------------------

#[test]
fn required_values_all_round_trip() {
    let json = serde_json::to_string(&RequiredValues::All).unwrap();
    assert_eq!(json, r#""*""#);
    let back: RequiredValues = serde_json::from_str(&json).unwrap();
    assert_eq!(back, RequiredValues::All);
}

#[test]
fn required_values_fields_round_trip() {
    let v = RequiredValues::Fields(vec!["powerGenerating".to_owned(), "batterySoC".to_owned()]);
    let json = serde_json::to_string(&v).unwrap();
    assert_eq!(json, r#""powerGenerating, batterySoC""#);
    let back: RequiredValues = serde_json::from_str(&json).unwrap();
    assert_eq!(back, v);
}

// ---------------------------------------------------------------------------
// historicData — request
// ---------------------------------------------------------------------------

#[test]
fn historic_request_serializes_correctly() {
    let req = HistoricRequest::new(
        vec!["ZA1ES111H1C029".to_owned(), "ZE1ES330M3E696".to_owned()],
        "2021-09-15T00:00:00.000Z",
        "2021-09-15T23:59:59.059Z",
    );

    let json: serde_json::Value = serde_json::to_value(&req).unwrap();

    assert_eq!(json["historicData"]["command"], "historicData");
    assert_eq!(
        json["historicData"]["params"]["thingKey"],
        "ZA1ES111H1C029, ZE1ES330M3E696"
    );
    assert_eq!(json["historicData"]["params"]["requiredValues"], "*");
    assert_eq!(
        json["historicData"]["params"]["start"],
        "2021-09-15T00:00:00.000Z"
    );
    assert_eq!(
        json["historicData"]["params"]["end"],
        "2021-09-15T23:59:59.059Z"
    );
}

#[test]
fn historic_request_deserializes_thing_keys() {
    let json = r#"{
        "historicData": {
            "command": "historicData",
            "params": {
                "thingKey": "ZA1ES111H1C029, ZE1ES330M3E696",
                "requiredValues": "*",
                "start": "2021-09-15T00:00:00.000Z",
                "end": "2021-09-15T23:59:59.059Z"
            }
        }
    }"#;

    let req: HistoricRequest = serde_json::from_str(json).unwrap();
    assert_eq!(
        req.historic_data.params.thing_keys,
        vec!["ZA1ES111H1C029", "ZE1ES330M3E696"]
    );
    assert_eq!(req.historic_data.params.required_values, RequiredValues::All);
}

// ---------------------------------------------------------------------------
// historicData — response
// ---------------------------------------------------------------------------

#[test]
fn historic_response_deserializes_from_spec_example() {
    let json = r#"{
        "historicData": {
            "params": {
                "value": [
                    {
                        "ZA1ES111H1C029": {
                            "powerGenerating": [490.0, 510.0],
                            "ts": ["2021-09-15T06:00:00Z", "2021-09-15T06:05:00Z"],
                            "energyGenerating": [0.8, 0.85],
                            "energyGeneratingTotal": [3874.0, 3874.85]
                        }
                    },
                    {
                        "ZE1ES330M3E696": {
                            "batterySoC": [17.0, 18.0],
                            "powerCharging": [0.0, 100.0],
                            "ts": ["2021-09-15T06:00:00Z", "2021-09-15T06:05:00Z"]
                        }
                    }
                ]
            },
            "success": true
        }
    }"#;

    let resp: HistoricResponse = serde_json::from_str(json).unwrap();
    assert!(resp.historic_data.success);

    let values = &resp.historic_data.params.value;
    assert_eq!(values.len(), 2);

    let device_a = values[0].get("ZA1ES111H1C029").unwrap();
    assert_eq!(
        device_a.power_generating.as_ref().unwrap(),
        &vec![490.0, 510.0]
    );
    assert_eq!(
        device_a.ts.as_ref().unwrap(),
        &vec!["2021-09-15T06:00:00Z", "2021-09-15T06:05:00Z"]
    );

    let device_b = values[1].get("ZE1ES330M3E696").unwrap();
    assert_eq!(device_b.battery_soc.as_ref().unwrap(), &vec![17.0, 18.0]);
    assert!(device_b.power_generating.is_none());
}

// ---------------------------------------------------------------------------
// realtimeData — request
// ---------------------------------------------------------------------------

#[test]
fn realtime_request_serializes_correctly() {
    let req = RealtimeRequest::new(vec![
        "ZA1ES111H1C029".to_owned(),
        "ZE1ES330M3E696".to_owned(),
    ]);

    let json: serde_json::Value = serde_json::to_value(&req).unwrap();

    assert_eq!(json["realtimeData"]["command"], "realtimeData");
    assert_eq!(
        json["realtimeData"]["params"]["thingKey"],
        "ZA1ES111H1C029, ZE1ES330M3E696"
    );
    assert_eq!(json["realtimeData"]["params"]["requiredValues"], "*");
}

// ---------------------------------------------------------------------------
// realtimeData — response
// ---------------------------------------------------------------------------

#[test]
fn realtime_response_deserializes_from_spec_example() {
    let json = r#"{
        "realtimeData": {
            "params": {
                "value": [
                    {
                        "ZA1ES111H1C029": {
                            "powerGenerating": 490,
                            "energyGenerating": 0.8,
                            "energyGeneratingTotal": 3874,
                            "thingFind": "2019-02-01T08:51:48Z",
                            "lastUpdate": "2022-01-10T09:53:13Z"
                        }
                    },
                    {
                        "ZE1ES330M3E696": {
                            "powerConsuming": 800,
                            "batterySoC": 17,
                            "powerGenerating": 570,
                            "energyGeneratingTotal": 3572,
                            "lastUpdate": "2022-01-10T09:44:11Z"
                        }
                    },
                    {
                        "2612280094": {
                            "energyExporting": 3601.65,
                            "powerImporting": 0,
                            "powerExporting": 171,
                            "lastUpdate": "2022-01-10T09:49:31Z"
                        }
                    }
                ]
            },
            "success": true
        }
    }"#;

    let resp: RealtimeResponse = serde_json::from_str(json).unwrap();
    assert!(resp.realtime_data.success);

    let values = &resp.realtime_data.params.value;
    assert_eq!(values.len(), 3);

    let inverter = values[0].get("ZA1ES111H1C029").unwrap();
    assert_eq!(inverter.power_generating, Some(490.0));
    assert_eq!(inverter.last_update.as_deref(), Some("2022-01-10T09:53:13Z"));
    assert_eq!(inverter.thing_find.as_deref(), Some("2019-02-01T08:51:48Z"));

    let hybrid = values[1].get("ZE1ES330M3E696").unwrap();
    assert_eq!(hybrid.battery_soc, Some(17.0));
    assert_eq!(hybrid.power_consuming, Some(800.0));

    let meter = values[2].get("2612280094").unwrap();
    assert_eq!(meter.energy_exporting, Some(3601.65));
    assert_eq!(meter.power_exporting, Some(171.0));
    assert!(meter.battery_soc.is_none());
}

// ---------------------------------------------------------------------------
// deviceAlarm — request
// ---------------------------------------------------------------------------

#[test]
fn device_alarm_request_serializes_correctly() {
    let req = DeviceAlarmRequest::new(vec![
        "ZA1ES122JAH761".to_owned(),
        "ZE1ES330M3E696".to_owned(),
    ]);

    let json: serde_json::Value = serde_json::to_value(&req).unwrap();

    assert_eq!(json["deviceAlarm"]["command"], "deviceAlarm");
    assert_eq!(
        json["deviceAlarm"]["params"]["thingKey"],
        "ZA1ES122JAH761, ZE1ES330M3E696"
    );
    assert_eq!(json["deviceAlarm"]["params"]["requiredValues"], "*");
}

// ---------------------------------------------------------------------------
// deviceAlarm — response
// ---------------------------------------------------------------------------

#[test]
fn device_alarm_response_deserializes_from_spec_example() {
    let json = r#"{
        "deviceAlarm": {
            "params": {
                "value": [
                    {
                        "ZA1ES122JAH761": {
                            "deviceAlarm": [2, 4],
                            "lastUpdate": "2022-10-24T09:32:49Z"
                        }
                    },
                    {
                        "ZE1ES330M3E696": {
                            "deviceAlarm": [],
                            "lastUpdate": "2022-10-24T09:46:03Z"
                        }
                    },
                    {
                        "2612280094": {}
                    }
                ]
            },
            "success": true
        }
    }"#;

    let resp: DeviceAlarmResponse = serde_json::from_str(json).unwrap();
    assert!(resp.device_alarm.success);

    let values = &resp.device_alarm.params.value;
    assert_eq!(values.len(), 3);

    let alarming = values[0].get("ZA1ES122JAH761").unwrap();
    assert_eq!(alarming.device_alarm.as_ref().unwrap(), &vec![2, 4]);
    assert_eq!(
        alarming.last_update.as_deref(),
        Some("2022-10-24T09:32:49Z")
    );

    let ok = values[1].get("ZE1ES330M3E696").unwrap();
    assert_eq!(ok.device_alarm.as_ref().unwrap(), &[] as &[u32]);

    let empty = values[2].get("2612280094").unwrap();
    assert!(empty.device_alarm.is_none());
    assert!(empty.last_update.is_none());
}
