use std::net::{Ipv4Addr, SocketAddr};
use url::Url;
use vector_lib::configurable::configurable_component;
#[configurable_component]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[serde(default, deny_unknown_fields)]
pub struct Options {
    #[serde(default = "default_enabled")]
    pub enabled: bool,
    #[serde(default = "default_address")]
    pub address: Option<SocketAddr>,
    #[serde(default = "default_playground")]
    pub playground: bool,
    #[serde(default = "default_graphql", skip_serializing_if = "is_true")]
    pub graphql: bool,
}
impl Default for Options {
    fn default() -> Self {
        Self {
            enabled: default_enabled(),
            playground: default_playground(),
            address: default_address(),
            graphql: default_graphql(),
        }
    }
}
#[allow(clippy::trivially_copy_pass_by_ref)]
const fn is_true(value: &bool) -> bool {
    *value
}
const fn default_enabled() -> bool {
    false
}
pub fn default_address() -> Option<SocketAddr> {
    Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 8686))
}
pub fn default_graphql_url() -> Url {
    let addr = default_address().unwrap();
    Url::parse(&format!("http://{}/graphql", addr))
        .expect("Couldn't parse default API URL. Please report this.")
}
const fn default_playground() -> bool {
    true
}
const fn default_graphql() -> bool {
    true
}
impl Options {
    pub fn merge(&mut self, other: Self) -> Result<(), String> {
        let address = match (self.address, other.address) {
            (None, b) => b,
            (Some(a), None) => Some(a),
            (Some(a), Some(b)) if a == b => Some(a),
            (Some(a), Some(b)) => {
                match (Some(a) == default_address(), Some(b) == default_address()) {
                    (false, false) => {
                        return Err(format!("Conflicting `api` address: {}, {} .", a, b))
                    }
                    (false, true) => Some(a),
                    (true, _) => Some(b),
                }
            }
        };
        let options = Options {
            address,
            enabled: self.enabled | other.enabled,
            playground: self.playground & other.playground,
            graphql: self.graphql & other.graphql,
        };
        *self = options;
        Ok(())
    }
}
#[test]
fn bool_merge() {
    let mut a = Options {
        enabled: true,
        address: None,
        playground: false,
        graphql: false,
    };
    a.merge(Options::default()).unwrap();
    assert_eq!(
        a,
        Options {
            enabled: true,
            address: default_address(),
            playground: false,
            graphql: false
        }
    );
}
#[test]
fn bind_merge() {
    let address = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9000);
    let mut a = Options {
        enabled: true,
        address: Some(address),
        playground: true,
        graphql: true,
    };
    a.merge(Options::default()).unwrap();
    assert_eq!(
        a,
        Options {
            enabled: true,
            address: Some(address),
            playground: true,
            graphql: true,
        }
    );
}
#[test]
fn bind_conflict() {
    let mut a = Options {
        address: Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9000)),
        ..Options::default()
    };
    let b = Options {
        address: Some(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9001)),
        ..Options::default()
    };
    assert!(a.merge(b).is_err());
}