1use crate::error::{
16    SdkApiError,
17    SdkError,
18};
19use crate::{
20    CoralogixRegion,
21    auth::AuthContext,
22    error::Result,
23    metadata::CallProperties,
24    util::make_request_with_metadata,
25};
26use crate::{
27    SDK_VERSION,
28    SDK_VERSION_HEADER_NAME,
29};
30use cx_api::proto::com::coralogixapis::alerts::v3::alert_defs_service_client::AlertDefsServiceClient;
31use cx_api::proto::com::coralogixapis::alerts::v3::{
32    CreateAlertDefRequest,
33    CreateAlertDefResponse,
34    DeleteAlertDefRequest,
35    GetAlertDefRequest,
36    GetAlertDefResponse,
37    ListAlertDefsRequest,
38    ListAlertDefsResponse,
39    ReplaceAlertDefRequest,
40    ReplaceAlertDefResponse,
41    SetActiveRequest,
42};
43
44use std::collections::HashMap;
45use std::str::FromStr;
46use tokio::sync::Mutex;
47use tonic::{
48    metadata::MetadataMap,
49    transport::{
50        Channel,
51        ClientTlsConfig,
52        Endpoint,
53    },
54};
55
56pub use cx_api::proto::com::coralogixapis::alerts::v3::{
57    ActivitySchedule,
58    ActivitySchedule as AlertDefActivitySchedule,
59    AlertDef,
60    AlertDefIncidentSettings,
61    AlertDefNotificationGroup,
62    AlertDefOverride,
63    AlertDefPriority,
64    AlertDefProperties,
65    AlertDefStatus,
66    AlertDefStatusFilter,
67    AlertDefType,
68    AlertDefWebhooksSettings,
69    AlertsOp,
70    AutoRetireTimeframe,
71    BurnRateThreshold,
72    BurnRateTypeDual,
73    BurnRateTypeSingle,
74    DayOfWeek as AlertDayOfWeek,
75    DayOfWeek,
76    DurationUnit,
77    ErrorBudgetThreshold,
78    FlowStages,
79    FlowStagesGroup,
80    FlowStagesGroups,
81    FlowStagesGroupsAlertDefs,
82    FlowType,
83    IntegrationType,
84    LabelFilterType,
85    LabelFilters,
86    LogFilterOperationType,
87    LogSeverity,
88    LogsAnomalyCondition,
89    LogsAnomalyConditionType,
90    LogsAnomalyRule,
91    LogsAnomalyType,
92    LogsFilter,
93    LogsImmediateType,
94    LogsNewValueCondition,
95    LogsNewValueRule,
96    LogsNewValueTimeWindow,
97    LogsNewValueTimeWindowValue,
98    LogsNewValueType,
99    LogsRatioCondition,
100    LogsRatioRules,
101    LogsRatioThresholdType,
102    LogsRatioTimeWindow,
103    LogsSimpleFilter,
104    LogsThresholdCondition,
105    LogsThresholdConditionType,
106    LogsThresholdRule,
107    LogsThresholdType,
108    LogsTimeRelativeCondition,
109    LogsTimeRelativeConditionType,
110    LogsTimeRelativeRule,
111    LogsTimeRelativeThresholdType,
112    LogsTimeWindow,
113    LogsTimeWindowValue,
114    LogsUniqueCountCondition,
115    LogsUniqueCountRule,
116    LogsUniqueCountType,
117    MetricAnomalyCondition,
118    MetricAnomalyRule,
119    MetricAnomalyType,
120    MetricMissingValues,
121    MetricThresholdType,
122    MetricTimeWindow,
123    MetricTimeWindowValue,
124    NextOp,
125    NotificationDestination,
126    NotificationRouter,
127    NotifyOn,
128    Recipients,
129    SloDefinition,
130    SloThresholdCondition,
131    SloThresholdRule,
132    SloThresholdType,
133    TimeDuration,
134    TimeOfDay,
135    TimeframeType,
136    TracingFilter,
137    TracingFilterOperationType,
138    TracingImmediateType,
139    TracingSimpleFilter,
140    TracingThresholdCondition,
141    TracingThresholdRule,
142    TracingThresholdType,
143    TracingTimeWindow,
144    TracingTimeWindowValue,
145    UndetectedValuesManagement,
146    alert_def_properties::{
147        Schedule,
148        TypeDefinition,
149    },
150    alert_def_webhooks_settings::*,
151    burn_rate_threshold::Type as BurnRateThresholdType,
152    integration_type,
153    logs_filter::FilterType,
154    logs_time_window::Type as LogsTimeWindowType,
155    metric_missing_values::MissingValues,
156    slo_threshold_type::Threshold,
157};
158
159const ALERTS_FEATURE_GROUP_ID: &str = "alerts";
160
161pub enum DefaultLabels {
163    SdkVersion,
165    Custom(HashMap<String, String>),
167}
168
169pub struct AlertsClient {
173    metadata_map: MetadataMap,
174    service_client: Mutex<AlertDefsServiceClient<Channel>>,
175    default_labels: HashMap<String, String>,
176}
177
178impl AlertsClient {
179    pub fn new(
185        region: CoralogixRegion,
186        auth_context: AuthContext,
187        default_labels: Option<DefaultLabels>,
188    ) -> Result<Self> {
189        let channel: Channel = Endpoint::from_str(®ion.grpc_endpoint())?
190            .tls_config(ClientTlsConfig::new().with_native_roots())?
191            .connect_lazy();
192        let request_metadata: CallProperties = (&auth_context.team_level_api_key).into();
193
194        let default_labels: HashMap<String, String> = match default_labels.as_ref() {
195            Some(labels) => match labels {
196                DefaultLabels::SdkVersion => default_label_hashmap(),
197                DefaultLabels::Custom(hash_map) => hash_map.clone(),
198            },
199            None => HashMap::new(),
200        };
201
202        Ok(Self {
203            metadata_map: request_metadata.to_metadata_map(),
204            service_client: Mutex::new(AlertDefsServiceClient::new(channel)),
205            default_labels,
206        })
207    }
208
209    pub async fn get(&self, alert_id: String) -> Result<GetAlertDefResponse> {
214        let request = make_request_with_metadata(
215            GetAlertDefRequest { id: Some(alert_id) },
216            &self.metadata_map,
217        );
218        {
219            let mut client = self.service_client.lock().await.clone();
220
221            client
222                .get_alert_def(request)
223                .await
224                .map(|r| r.into_inner())
225                .map_err(|status| {
226                    SdkError::ApiError(SdkApiError {
227                        status,
228                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/GetAlertDef"
229                            .into(),
230                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
231                    })
232                })
233        }
234    }
235
236    pub async fn list(&self) -> Result<ListAlertDefsResponse> {
238        let request = make_request_with_metadata(
239            ListAlertDefsRequest {
240                pagination: None,
241                query_filter: None,
242                ..Default::default()
243            },
244            &self.metadata_map,
245        );
246        {
247            let mut client = self.service_client.lock().await.clone();
248
249            client
250                .list_alert_defs(request)
251                .await
252                .map(|r| r.into_inner())
253                .map_err(|status| {
254                    SdkError::ApiError(SdkApiError {
255                        status,
256                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/ListAlertDefs"
257                            .into(),
258                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
259                    })
260                })
261        }
262    }
263
264    pub async fn create(&self, alert: AlertDef) -> Result<CreateAlertDefResponse> {
269        let request = make_request_with_metadata(
270            CreateAlertDefRequest {
271                alert_def_properties: alert.alert_def_properties.clone(),
272            },
273            &self.metadata_map,
274        );
275        {
276            let mut client = self.service_client.lock().await.clone();
277            let mut alert = alert;
278            if let Some(alert_def) = &mut alert.alert_def_properties {
279                let _ = self
280                    .default_labels
281                    .clone()
282                    .into_iter()
283                    .map(|(k, v)| alert_def.entity_labels.insert(k, v));
284            }
285            client
286                .create_alert_def(request)
287                .await
288                .map(|r| r.into_inner())
289                .map_err(|status| {
290                    SdkError::ApiError(SdkApiError {
291                        status,
292                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/CreateAlertDef"
293                            .into(),
294                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
295                    })
296                })
297        }
298    }
299
300    pub async fn replace(&self, alert: AlertDef) -> Result<ReplaceAlertDefResponse> {
304        let mut alert = alert;
305        if let Some(alert_def) = &mut alert.alert_def_properties {
306            let _ = self
307                .default_labels
308                .clone()
309                .into_iter()
310                .map(|(k, v)| alert_def.entity_labels.insert(k, v));
311        }
312
313        let request = make_request_with_metadata(
314            ReplaceAlertDefRequest {
315                alert_def_properties: alert.alert_def_properties,
316                id: alert.id,
317            },
318            &self.metadata_map,
319        );
320        {
321            let mut client = self.service_client.lock().await.clone();
322
323            client
324                .replace_alert_def(request)
325                .await
326                .map(|r| r.into_inner())
327                .map_err(|status| {
328                    SdkError::ApiError(SdkApiError {
329                        status,
330                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/ReplaceAlertDef"
331                            .into(),
332                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
333                    })
334                })
335        }
336    }
337
338    pub async fn delete(&self, alert_id: String) -> Result<()> {
342        let request = make_request_with_metadata(
343            DeleteAlertDefRequest { id: Some(alert_id) },
344            &self.metadata_map,
345        );
346        {
347            let mut client = self.service_client.lock().await.clone();
348            client
349                .delete_alert_def(request)
350                .await
351                .map(|_| ())
352                .map_err(|status| {
353                    SdkError::ApiError(SdkApiError {
354                        status,
355                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/DeleteAlertDef"
356                            .into(),
357                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
358                    })
359                })
360        }
361    }
362
363    pub async fn set(&self, id: String, active: bool) -> Result<()> {
368        let request = make_request_with_metadata(
369            SetActiveRequest {
370                id: Some(id),
371                active: Some(active),
372            },
373            &self.metadata_map,
374        );
375        {
376            let mut client = self.service_client.lock().await.clone();
377            client
378                .set_active(request)
379                .await
380                .map(|_| ())
381                .map_err(|status| {
382                    SdkError::ApiError(SdkApiError {
383                        status,
384                        endpoint: "/com.coralogixapis.alerts.v3.AlertDefsService/SetActive".into(),
385                        feature_group: ALERTS_FEATURE_GROUP_ID.into(),
386                    })
387                })
388        }
389    }
390}
391
392fn default_label_hashmap() -> HashMap<String, String> {
393    let mut hm = HashMap::new();
394    hm.insert(SDK_VERSION_HEADER_NAME.to_string(), SDK_VERSION.to_string());
395    hm
396}