seamless-glance 1.0.0

Fast, read-only AWS TUI for cloud infrastructure visibility and triage
use crate::app::App;
use crate::models::cloudwatch::{CloudWatchAlarm, CloudWatchSummary};
use crate::models::service_status::ServiceStatus;

pub async fn fetch_cloudwatch(app: &App) -> (CloudWatchSummary, Vec<CloudWatchAlarm>) {
    let resp = match app.aws.cw.describe_alarms().send().await {
        Ok(r) => r,
        Err(err) => {
            let msg = err.to_string();
            let status = if msg.contains("AccessDenied") {
                ServiceStatus::AccessDenied
            } else {
                ServiceStatus::Unavailable(msg)
            };

            return (
                CloudWatchSummary {
                    status,
                    total_alarms: 0,
                    alarms_in_alarm: 0,
                },
                vec![],
            );
        }
    };

    let alarms: Vec<CloudWatchAlarm> = resp
        .metric_alarms()
        .iter()
        .map(|a| CloudWatchAlarm {
            name: a.alarm_name().unwrap_or("").to_string(),
            state: a
                .state_value()
                .map(|s| s.as_str())
                .unwrap_or("UNKNOWN")
                .to_string(),
            namespace: a.namespace().unwrap_or("").to_string(),
            metric: a.metric_name().unwrap_or("").to_string(),
        })
        .collect();
    let mut alarms = alarms;
    alarms.sort_by(|a, b| {
        let a_rank = if a.state == "ALARM" { 0 } else { 1 };
        let b_rank = if b.state == "ALARM" { 0 } else { 1 };

        a_rank
            .cmp(&b_rank)
            .then_with(|| a.name.cmp(&b.name))
            .then_with(|| a.namespace.cmp(&b.namespace))
    });

    let total = alarms.len();
    let alarming = alarms.iter().filter(|a| a.state == "ALARM").count();

    (
        CloudWatchSummary {
            status: ServiceStatus::Ok,
            total_alarms: total,
            alarms_in_alarm: alarming,
        },
        alarms,
    )
}