use std::borrow::Cow;
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct ConfigParameters {
    values: String,
}
impl ConfigParameters {
    pub fn new() -> Self {
        let values = std::env::var("GIT_CONFIG_PARAMETERS").unwrap_or_else(|_| Default::default());
        Self { values }
    }
    pub fn iter(&self) -> ConfigParametersIter<'_> {
        self.into_iter()
    }
}
impl<'s> IntoIterator for &'s ConfigParameters {
    type Item = (Cow<'s, str>, Option<Cow<'s, str>>);
    type IntoIter = ConfigParametersIter<'s>;
    fn into_iter(self) -> Self::IntoIter {
        Self::IntoIter::new(&self.values)
    }
}
#[derive(Clone, Default, Debug, PartialEq, Eq)]
pub struct ConfigParametersIter<'s> {
    values: &'s str,
}
impl<'s> ConfigParametersIter<'s> {
    pub fn new(values: &'s str) -> Self {
        Self { values }
    }
    pub fn iter(&self) -> impl Iterator<Item = (Cow<str>, Cow<str>)> + '_ {
        None.into_iter()
    }
}
impl<'s> Iterator for ConfigParametersIter<'s> {
    type Item = (Cow<'s, str>, Option<Cow<'s, str>>);
    fn next(&mut self) -> Option<Self::Item> {
        self.values = self.values.trim_start();
        let key = crate::quote::sq_dequote(&mut self.values).ok()?;
        if let Some(values) = self.values.strip_prefix('=') {
            self.values = values;
            if self.values.is_empty() {
                Some((key, None))
            } else if let Some(values) = self.values.strip_prefix(' ') {
                self.values = values;
                Some((key, None))
            } else {
                let value = crate::quote::sq_dequote(&mut self.values).ok()?;
                Some((key, Some(value)))
            }
        } else {
            if self.values.is_empty() {
                Some(parse_parameter_cow(key))
            } else if let Some(values) = self.values.strip_prefix(' ') {
                self.values = values;
                Some(parse_parameter_cow(key))
            } else {
                self.values = "";
                None
            }
        }
    }
}
#[cfg(test)]
mod test_env {
    use super::*;
    #[test]
    fn empty() {
        let fixture = "";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(actual, vec![]);
    }
    #[test]
    fn test_old() {
        let fixture = "'delta.plus-style=green'";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(
            actual,
            vec![(
                Cow::Borrowed("delta.plus-style"),
                Some(Cow::Borrowed("green"))
            )]
        );
    }
    #[test]
    fn test_old_bool() {
        let fixture = "'delta.plus-style'";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(actual, vec![(Cow::Borrowed("delta.plus-style"), None)]);
    }
    #[test]
    fn test_old_multiple() {
        let fixture = "'delta.plus-style=green' 'delta.plus-style' 'delta.plus-style=green'";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(
            actual,
            vec![
                (
                    Cow::Borrowed("delta.plus-style"),
                    Some(Cow::Borrowed("green"))
                ),
                (Cow::Borrowed("delta.plus-style"), None),
                (
                    Cow::Borrowed("delta.plus-style"),
                    Some(Cow::Borrowed("green"))
                ),
            ]
        );
    }
    #[test]
    fn test_new() {
        let fixture = "'delta.plus-style'='green'";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(
            actual,
            vec![(
                Cow::Borrowed("delta.plus-style"),
                Some(Cow::Borrowed("green"))
            )]
        );
    }
    #[test]
    fn test_new_bool() {
        let fixture = "'delta.plus-style'=";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(actual, vec![(Cow::Borrowed("delta.plus-style"), None)]);
    }
    #[test]
    fn test_new_multiple() {
        let fixture = "'delta.plus-style'='green' 'delta.plus-style'= 'delta.plus-style'='green'";
        let config = ConfigParametersIter::new(fixture);
        let actual: Vec<_> = config.collect();
        assert_eq!(
            actual,
            vec![
                (
                    Cow::Borrowed("delta.plus-style"),
                    Some(Cow::Borrowed("green"))
                ),
                (Cow::Borrowed("delta.plus-style"), None),
                (
                    Cow::Borrowed("delta.plus-style"),
                    Some(Cow::Borrowed("green"))
                ),
            ]
        );
    }
}
pub fn parse_parameter(arg: &str) -> (&str, Option<&str>) {
    arg.split_once('=')
        .map(|(k, v)| (k, Some(v)))
        .unwrap_or((arg, None))
}
fn parse_parameter_cow(arg: Cow<str>) -> (Cow<str>, Option<Cow<str>>) {
    match arg {
        Cow::Borrowed(arg) => {
            let (key, value) = parse_parameter(arg);
            (Cow::Borrowed(key), value.map(Cow::Borrowed))
        }
        Cow::Owned(arg) => {
            let (key, value) = parse_parameter(arg.as_str());
            (
                Cow::Owned(key.to_owned()),
                value.map(|v| Cow::Owned(v.to_owned())),
            )
        }
    }
}
#[cfg(test)]
mod test_parse_parameter {
    use super::*;
    #[test]
    fn basic() {
        let fixture = "key=value";
        let expected = ("key", Some("value"));
        let actual = parse_parameter(fixture);
        assert_eq!(actual, expected);
    }
    #[test]
    fn implied_bool() {
        let fixture = "key";
        let expected = ("key", None);
        let actual = parse_parameter(fixture);
        assert_eq!(actual, expected);
    }
    #[test]
    fn multiple_eq() {
        let fixture = "section.subsection=with=equals.key=value";
        let expected = ("section.subsection", Some("with=equals.key=value"));
        let actual = parse_parameter(fixture);
        assert_eq!(actual, expected);
    }
}