use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use vector_lib::configurable::configurable_component;
pub mod cloud_storage;
pub mod pubsub;
pub mod stackdriver;
#[configurable_component]
#[derive(Clone, Debug, Default)]
pub struct GcpTypedResource {
    #[configurable(metadata(docs::examples = "global", docs::examples = "gce_instance"))]
    pub r#type: String,
    #[serde(flatten)]
    #[configurable(metadata(
        docs::additional_props_description = "Values for all of the labels listed in the associated monitored resource descriptor.\n\nFor example, Compute Engine VM instances use the labels `projectId`, `instanceId`, and `zone`."
    ))]
    #[configurable(metadata(docs::examples = "label_examples()"))]
    pub labels: HashMap<String, String>,
}
fn label_examples() -> HashMap<String, String> {
    let mut example = HashMap::new();
    example.insert("type".to_string(), "global".to_string());
    example.insert("projectId".to_string(), "vector-123456".to_string());
    example.insert("instanceId".to_string(), "Twilight".to_string());
    example.insert("zone".to_string(), "us-central1-a".to_string());
    example
}
#[derive(Deserialize, Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "UPPERCASE")]
pub enum GcpMetricKind {
    Cumulative,
    Gauge,
}
#[derive(Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "UPPERCASE")]
pub enum GcpValueType {
    Int64,
}
#[derive(Serialize, Debug, Clone, Copy)]
pub struct GcpPoint {
    pub interval: GcpInterval,
    pub value: GcpPointValue,
}
#[derive(Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub struct GcpInterval {
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "serialize_optional_datetime"
    )]
    pub start_time: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(serialize_with = "serialize_datetime")]
    pub end_time: chrono::DateTime<chrono::Utc>,
}
#[derive(Serialize, Debug, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub struct GcpPointValue {
    #[serde(
        skip_serializing_if = "Option::is_none",
        serialize_with = "serialize_int64_value"
    )]
    pub int64_value: Option<i64>,
}
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GcpMetric {
    pub r#type: String,
    pub labels: HashMap<String, String>,
}
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GcpResource {
    pub r#type: String,
    pub labels: HashMap<String, String>,
}
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GcpSerie {
    pub metric: GcpMetric,
    pub resource: GcpResource,
    pub metric_kind: GcpMetricKind,
    pub value_type: GcpValueType,
    pub points: Vec<GcpPoint>,
}
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct GcpSeries<'a> {
    time_series: &'a [GcpSerie],
}
fn serialize_int64_value<S>(value: &Option<i64>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    serializer.serialize_str(value.as_ref().expect("always defined").to_string().as_str())
}
fn serialize_datetime<S>(
    value: &chrono::DateTime<chrono::Utc>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    serializer.serialize_str(
        value
            .to_rfc3339_opts(chrono::SecondsFormat::Nanos, true)
            .as_str(),
    )
}
fn serialize_optional_datetime<S>(
    value: &Option<chrono::DateTime<chrono::Utc>>,
    serializer: S,
) -> Result<S::Ok, S::Error>
where
    S: serde::Serializer,
{
    serialize_datetime(value.as_ref().expect("always defined"), serializer)
}
#[cfg(test)]
mod tests {
    use super::*;
    use chrono::TimeZone;
    #[test]
    fn serialize_gcp_series() {
        let end_time = chrono::Utc
            .with_ymd_and_hms(2023, 2, 14, 10, 0, 0)
            .single()
            .expect("invalid timestamp");
        let gcp_series = GcpSeries {
            time_series: &[GcpSerie {
                metric: GcpMetric {
                    r#type: "custom.googleapis.com/my_namespace/metrics/my_metric".to_string(),
                    labels: [(
                        "my_metric_label".to_string(),
                        "my_metric_label_value".to_string(),
                    )]
                    .into(),
                },
                resource: GcpResource {
                    r#type: "my_resource".to_string(),
                    labels: [(
                        "my_resource_label".to_string(),
                        "my_resource_label_value".to_string(),
                    )]
                    .into(),
                },
                metric_kind: GcpMetricKind::Gauge,
                value_type: GcpValueType::Int64,
                points: vec![GcpPoint {
                    interval: GcpInterval {
                        start_time: None,
                        end_time,
                    },
                    value: GcpPointValue {
                        int64_value: Some(10),
                    },
                }],
            }],
        };
        let serialized = serde_json::to_string(&gcp_series).unwrap();
        let value: serde_json::Value = serde_json::from_str(&serialized).unwrap();
        let expected: serde_json::Value = serde_json::from_str(r#"{"timeSeries":[{"metric":{"type":"custom.googleapis.com/my_namespace/metrics/my_metric","labels":{"my_metric_label":"my_metric_label_value"}},"resource":{"type":"my_resource","labels":{"my_resource_label":"my_resource_label_value"}},"metricKind":"GAUGE","valueType": "INT64","points":[{"interval":{"endTime":"2023-02-14T10:00:00.000000000Z"},"value":{"int64Value":"10"}}]}]}"#).unwrap();
        assert_eq!(value, expected);
    }
}