//! Gateway notification polling — pure event formatting.
//!
//! Formats pipeline events from project containers into gateway notifications
//! with `[project-name]` prefixes. The actual I/O (HTTP polling, spawning
//! tasks, sending messages) lives in `io.rs`.

use crate::service::events::StoredEvent;
use crate::service::notifications::{
    format_blocked_notification, format_error_notification, format_stage_notification,
    stage_display_name,
};

/// Format a [`StoredEvent`] from a project into a gateway notification.
///
/// Prefixes the message with `[project-name]` so users can distinguish which
/// project emitted the event.
pub fn format_gateway_event(project_name: &str, event: &StoredEvent) -> (String, String) {
    let prefix = format!("[{project_name}] ");

    match event {
        StoredEvent::StageTransition {
            story_id,
            from_stage,
            to_stage,
            ..
        } => {
            let from_display = stage_display_name(from_stage);
            let to_display = stage_display_name(to_stage);
            let (plain, html) = format_stage_notification(story_id, None, from_display, to_display);
            (format!("{prefix}{plain}"), format!("{prefix}{html}"))
        }
        StoredEvent::MergeFailure {
            story_id, reason, ..
        } => {
            let (plain, html) = format_error_notification(story_id, None, reason);
            (format!("{prefix}{plain}"), format!("{prefix}{html}"))
        }
        StoredEvent::StoryBlocked {
            story_id, reason, ..
        } => {
            let (plain, html) = format_blocked_notification(story_id, None, reason);
            (format!("{prefix}{plain}"), format!("{prefix}{html}"))
        }
    }
}

// ── Tests ────────────────────────────────────────────────────────────────────

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn stage_transition_prefixes_project_name() {
        let event = StoredEvent::StageTransition {
            story_id: "42_story_my_feature".to_string(),
            from_stage: "2_current".to_string(),
            to_stage: "3_qa".to_string(),
            timestamp_ms: 1000,
        };
        let (plain, html) = format_gateway_event("huskies", &event);
        assert!(plain.starts_with("[huskies] "));
        assert!(html.starts_with("[huskies] "));
        assert!(plain.contains("Current"));
        assert!(plain.contains("QA"));
    }

    #[test]
    fn merge_failure_prefixes_project_name() {
        let event = StoredEvent::MergeFailure {
            story_id: "42_story_my_feature".to_string(),
            reason: "merge conflict".to_string(),
            timestamp_ms: 1000,
        };
        let (plain, _html) = format_gateway_event("robot-studio", &event);
        assert!(plain.starts_with("[robot-studio] "));
        assert!(plain.contains("merge conflict"));
    }

    #[test]
    fn story_blocked_prefixes_project_name() {
        let event = StoredEvent::StoryBlocked {
            story_id: "43_story_bar".to_string(),
            reason: "retry limit exceeded".to_string(),
            timestamp_ms: 2000,
        };
        let (plain, _html) = format_gateway_event("huskies", &event);
        assert!(plain.starts_with("[huskies] "));
        assert!(plain.contains("BLOCKED"));
    }
}
