conditions 0.3.0

Fetch basic weather conditions for current or specified location
Documentation
use std::fmt;

use crate::{api::Fetchable, config::Config, location::Location};

pub(crate) mod open_meteo;
pub(crate) mod weather_api;

#[derive(Debug)]
pub struct CurrentConditions {
    pub temp_c: f32,
    pub temp_f: f32,
    pub icon: String,
}

pub trait Provider {
    fn current(&self) -> eyre::Result<CurrentConditions>;
    fn query_pairs(&self) -> Vec<(&str, &str)>;
}

#[derive(Clone, Debug)]
pub enum Source {
    WeatherAPI,
    OpenMeteo,
}

impl fmt::Display for Source {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let name = match self {
            Source::WeatherAPI => "WeatherAPI",
            Source::OpenMeteo => "OpenMeteo",
        };
        write!(f, "{name}")
    }
}

impl CurrentConditions {
    pub fn get(
        config: &Config,
        location: &Location,
    ) -> eyre::Result<CurrentConditions> {
        let sources = vec![Source::WeatherAPI, Source::OpenMeteo];

        for source in &sources {
            let result = match source {
                Source::WeatherAPI => {
                    weather_api::Client::new(config, location).fetch()
                }
                Source::OpenMeteo => {
                    open_meteo::Client::new(config, location).fetch()
                }
            };

            if result.is_ok() {
                return result;
            }
        }

        Err(eyre::eyre!("no weather providers succeeded"))
    }
}

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

    #[test]
    fn it_converts_provider_to_string() {
        assert_eq!(Source::WeatherAPI.to_string(), "WeatherAPI");
        assert_eq!(Source::OpenMeteo.to_string(), "OpenMeteo");
    }
}