package com.airlock.iam.application.parameters.infrastructure;

import com.airlock.iam.application.parameters.domain.model.ParameterSpec;
import com.airlock.iam.system.config.ConfigFormat;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class InstancePropertiesTemplate {
   private static final Pattern PARAMETER_TOKEN = Pattern.compile("@([^@]+)@");
   private static final Pattern ESCAPE = Pattern.compile("[:=]");

   public static String instancePropertiesTemplate(InstancePropertiesTemplate.Variant variant, ConfigFormat format) {
      String template = getTemplate();
      Matcher matcher = PARAMETER_TOKEN.matcher(template);
      Map<ParameterSpec, String> implicitDefaults = ParametersLoader.loadDefaultParameters();
      Map<ParameterSpec, String> explicitDefaults = getExplicitDefaults(variant, format);
      return matcher.replaceAll(r -> {
         String key = matcher.group(1);
         ParameterSpec parameter = ParameterSpec.ofPropertyFileKey(key);
         return Matcher.quoteReplacement(getDefaultsString(parameter, implicitDefaults.get(parameter), explicitDefaults.get(parameter)));
      });
   }

   private static String getTemplate() {
      try (InputStream in = Objects.requireNonNull(ParametersLoader.class.getResourceAsStream("instance.properties.template"))) {
         return new String(in.readAllBytes(), StandardCharsets.UTF_8);
      } catch (IOException e) {
         throw new IllegalStateException(e);
      }
   }

   private static String getDefaultsString(ParameterSpec parameter, String implicitDefault, String explicitDefault) {
      StringBuilder result = new StringBuilder("#").append(formatProperty(parameter.propertyFileKey(), implicitDefault));
      if (explicitDefault != null) {
         result.append("\n");
         result.append(formatProperty(parameter.propertyFileKey(), explicitDefault));
      }

      return result.toString();
   }

   private static String formatProperty(String key, String value) {
      String escaped = value == null ? "" : ESCAPE.matcher(value).replaceAll("\\\\$0");
      return String.format("%s = %s", key, escaped);
   }

   private static Map<ParameterSpec, String> getExplicitDefaults(InstancePropertiesTemplate.Variant variant, ConfigFormat format) {
      Map<ParameterSpec, String> defaults = new HashMap<>();
      if (variant == InstancePropertiesTemplate.Variant.DOCKER) {
         defaults.put(ParameterSpec.LOG_STRUCTURED_STDOUT_ENABLED, "true");
         defaults.put(ParameterSpec.WEB_SERVER_LOG_CONSOLE_FORMAT, "structured");
      } else {
         defaults.put(ParameterSpec.LOG_STRUCTURED_FILE_ENABLED, "true");
      }

      if (format == ConfigFormat.YAML_FORMAT) {
         defaults.put(ParameterSpec.PLUGIN_CONFIG_FORMAT, "yaml");
      }

      return defaults;
   }

   private InstancePropertiesTemplate() {
      throw new AssertionError();
   }

   public enum Variant {
      DEFAULT,
      DOCKER;
   }
}
