//! Fan a single request out to every registered source.

use std::sync::Arc;

use aerocontext_core::{AreaBriefingRequest, Briefing, ProviderError, WeatherBriefingProvider};

/// One source's result for a gathered request, tagged with its source
/// name so a failure is still attributable.
#[derive(Debug)]
pub struct GatherOutcome {
    /// [`crate::ContextProvider::name`] of the source.
    pub source: String,
    /// The briefing, or the error that source returned.
    pub result: Result<Briefing, ProviderError>,
}

impl GatherOutcome {
    /// The briefing if this source succeeded.
    pub fn briefing(&self) -> Option<&Briefing> {
        self.result.as_ref().ok()
    }
}

/// Request a briefing from each source in turn.
///
/// Sequential by design: providers (notably AWC) ask for low request
/// concurrency, and one slow or failing source must not abort the others
/// — every source yields its own [`GatherOutcome`].
pub async fn gather(
    sources: &[Arc<dyn WeatherBriefingProvider>],
    request: &AreaBriefingRequest,
) -> Vec<GatherOutcome> {
    let mut outcomes = Vec::with_capacity(sources.len());
    for source in sources {
        let result = source.area_briefing(request).await;
        outcomes.push(GatherOutcome {
            source: source.name().to_owned(),
            result,
        });
    }
    outcomes
}

/// The successful briefings from a set of outcomes, ready for
/// [`compare()`](aerocontext_core::compare()).
pub fn successful_briefings(outcomes: &[GatherOutcome]) -> Vec<Briefing> {
    outcomes
        .iter()
        .filter_map(|o| o.briefing().cloned())
        .collect()
}
