use std::collections::BTreeMap;

use kube::CustomResource;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::modules::monitoring::kube_prometheus::types::Operator;

#[derive(CustomResource, Serialize, Deserialize, Debug, Clone, JsonSchema)]
#[kube(
    group = "monitoring.coreos.com",
    version = "v1",
    kind = "Prometheus",
    plural = "prometheuses",
    namespaced
)]
#[serde(rename_all = "camelCase")]
pub struct PrometheusSpec {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub alerting: Option<PrometheusSpecAlerting>,

    pub service_account_name: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub service_monitor_namespace_selector: Option<LabelSelector>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub service_monitor_selector: Option<LabelSelector>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub service_discovery_role: Option<String>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub pod_monitor_selector: Option<LabelSelector>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rule_selector: Option<LabelSelector>,

    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub rule_namespace_selector: Option<LabelSelector>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "camelCase")]
pub struct NamespaceSelector {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub match_names: Vec<String>,
}

/// Contains alerting configuration, specifically Alertmanager endpoints.
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
pub struct PrometheusSpecAlerting {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub alertmanagers: Option<Vec<AlertmanagerEndpoints>>,
}

/// Represents an Alertmanager endpoint configuration used by Prometheus.
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
pub struct AlertmanagerEndpoints {
    /// Name of the Alertmanager Service.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// Namespace of the Alertmanager Service.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub namespace: Option<String>,

    /// Port to access on the Alertmanager Service (e.g. "web").
    #[serde(skip_serializing_if = "Option::is_none")]
    pub port: Option<String>,

    /// Scheme to use for connecting (e.g. "http").
    #[serde(skip_serializing_if = "Option::is_none")]
    pub scheme: Option<String>,
    // Other fields like `tls_config`, `path_prefix`, etc., can be added if needed.
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
#[serde(rename_all = "camelCase")]
pub struct LabelSelector {
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub match_labels: BTreeMap<String, String>,

    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub match_expressions: Vec<LabelSelectorRequirement>,
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct LabelSelectorRequirement {
    pub key: String,
    pub operator: Operator,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub values: Vec<String>,
}

impl Default for PrometheusSpec {
    fn default() -> Self {
        PrometheusSpec {
            alerting: None,

            service_account_name: "prometheus".into(),

            // null means "only my namespace"
            service_monitor_namespace_selector: None,

            // empty selector means match all ServiceMonitors in that namespace
            service_monitor_selector: Some(LabelSelector::default()),

            service_discovery_role: Some("Endpoints".into()),

            pod_monitor_selector: None,

            rule_selector: None,

            rule_namespace_selector: Some(LabelSelector::default()),
        }
    }
}
