/* https://www.gnu.org/licenses/gpl-3.0.en.html */
package your.app;

import java.util.Arrays;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

/**
 * Spring boot application listener that prepares the application environment based on the
 * <code>--env=(dev|pprd|prod)</code> program option (primary) or <code>env</code> system property (backup).
 *
 * @author Marvin S. Addison
 */
public class EnvSpringApplicationRunListener implements SpringApplicationRunListener {
  /** Name of program option that holds deployment environment name. */
  public static final String ENV_ARG_PREFIX = "--env";

  /** Name of property that holds deployment environment name. */
  public static final String ENV_PROP = "env";

  /** Recognized deployment environments. */
  private static final List<String> SUPPORTED_ENVIRONMENTS = Arrays.asList("build", "dev", "pprd", "prod");

  /** Logger instance. */
  private final Logger logger = LoggerFactory.getLogger(EnvSpringApplicationRunListener.class);

  /** Spring Boot application instance. */
  private final SpringApplication application;

  /** Program arguments. */
  private final String[] args;


  /**
   * Creates a new instance.
   *
   * @param app Spring Boot application instance.
   * @param programArgs Program arguments.
   */
  public EnvSpringApplicationRunListener(final SpringApplication app, final String[] programArgs) {
    application = app;
    args = programArgs;
  }

  @Override
  public void starting() {
    final String env = getEnv();
    if (!SUPPORTED_ENVIRONMENTS.contains(env)) {
      throw new IllegalStateException("Unsupported deployment environment: " + env);
    }
    application.setAdditionalProfiles(env);
  }

  @Override
  public void environmentPrepared(final ConfigurableEnvironment environment) {}

  @Override
  public void contextPrepared(final ConfigurableApplicationContext context) {}

  @Override
  public void contextLoaded(final ConfigurableApplicationContext context) {}

  @Override
  public void started(final ConfigurableApplicationContext context) {}

  @Override
  public void running(final ConfigurableApplicationContext context) {}

  @Override
  public void failed(final ConfigurableApplicationContext context, final Throwable exception) {}


  /** @return Application environment name. */
  public String getEnv() {
    for (String arg : args) {
      if (arg.startsWith(ENV_ARG_PREFIX)) {
        final String[] parts = arg.split("=");
        if (parts.length == 2) {
          logger.info("Setting application environment to {} based on {} program option", parts[1], ENV_ARG_PREFIX);
          return parts[1];
        }
      }
    }
    logger.info("Deployment environment not found in program options. Checking system properties");
    final String env = System.getProperty(ENV_PROP);
    if (env != null) {
      return env;
    }
    throw new IllegalStateException("Cannot determine deployment environment. Please set either '" +
      ENV_ARG_PREFIX + "' program option or '" +
      ENV_PROP + "' system property");
  }
}