Documentation
// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

use crate::services::flex::gcl::ToGcl;
use indoc::formatdoc;

/// Configuration for a local Service.
#[derive(Debug, Clone)]
pub struct UpstreamServiceConfig {
    name: String,
    address: String,
}

impl UpstreamServiceConfig {
    fn new() -> Self {
        Self {
            name: "upstream-service".to_string(),
            address: "http://upstream-service".to_string(),
        }
    }

    /// Creates a builder for initialize a [`ServiceConfig`].
    pub fn builder() -> UpstreamServiceConfigBuilder {
        UpstreamServiceConfigBuilder::new()
    }
}

/// A builder for initilizing a [`ServiceConfig`].
#[derive(Debug, Clone)]
pub struct UpstreamServiceConfigBuilder {
    config: UpstreamServiceConfig,
}

impl UpstreamServiceConfigBuilder {
    fn new() -> Self {
        Self {
            config: UpstreamServiceConfig::new(),
        }
    }

    /// Set the upstream service address.
    pub fn address<T: Into<String>>(self, address: T) -> Self {
        Self {
            config: UpstreamServiceConfig {
                address: address.into(),
                ..self.config
            },
        }
    }

    /// Set the upstream service name.
    pub fn name<T: Into<String>>(self, name: T) -> Self {
        Self {
            config: UpstreamServiceConfig {
                name: name.into(),
                ..self.config
            },
        }
    }

    /// Builds a new [`ServiceConfig`].
    pub fn build(self) -> UpstreamServiceConfig {
        self.config
    }
}

impl ToGcl for UpstreamServiceConfig {
    // NOTE: If in the future we need to support non-compact policy GCLs (to apply policies to
    // services) we'll need change the api GCL to the non-compact one.
    fn to_gcl(&self) -> String {
        let name = self.name.as_str();
        let address = self.address.as_str();

        formatdoc!(
            "
        # Copyright (c) 2026, Salesforce, Inc.,
        # All rights reserved.
        # For full license text, see the LICENSE.txt file
        ---
        apiVersion: gateway.mulesoft.com/v1alpha1
        kind: Service
        metadata:
          name: {name}
        spec:
          address: {address}"
        )
    }

    fn name(&self) -> &str {
        &self.name
    }
}

#[cfg(test)]
mod tests {
    use crate::services::flex::gcl::ToGcl as _;
    use crate::services::flex::UpstreamServiceConfig;
    use indoc::formatdoc;

    #[test]
    fn generate_service_gcl() {
        let service_config = UpstreamServiceConfig::builder()
            .name("gripmock")
            .address("h2://gripmock:4770")
            .build();

        let expected = formatdoc!(
            r#"
        # Copyright (c) 2026, Salesforce, Inc.,
        # All rights reserved.
        # For full license text, see the LICENSE.txt file
        ---
        apiVersion: gateway.mulesoft.com/v1alpha1
        kind: Service
        metadata:
          name: gripmock
        spec:
          address: h2://gripmock:4770"#
        );

        assert_eq!(service_config.to_gcl(), expected);
    }
}