package com.airlock.iam.sensitivevalues.application.service;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
import java.util.function.Consumer;

public final class SensitiveValuesHelper {
   private static final String JAVA_CLASS_PROPERTY = "sensitive-values-provider";
   public static final String LEGACY_JCEKS_PROVIDER_CLASS_NAME = "ch.ergon.iam.sensitive.JceksSensitiveValuesProvider";

   private SensitiveValuesHelper() {
   }

   public static SensitiveValuesProvider getProvider(FileLocationResolver fileLocationResolver, File configFile, Consumer<String> warningLogger) throws Exception {
      Properties properties = new Properties();
      Path file = fileLocationResolver.resolveFileLocation(configFile.toString()).toPath();

      try (InputStream instream = Files.newInputStream(file)) {
         properties.load(instream);
         return createProviderInstance(getProviderClassName(properties, warningLogger), properties, fileLocationResolver);
      }
   }

   private static SensitiveValuesProvider createProviderInstance(String classname, Properties allProperties, FileLocationResolver fileLocationResolver) throws IllegalArgumentException, ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException {
      if (classname != null && !classname.isEmpty()) {
         Class<?> clazz = Class.forName(classname);
         if (!SensitiveValuesProvider.class.isAssignableFrom(clazz)) {
            throw new IllegalArgumentException("Specified class must implement " + SensitiveValuesProvider.class.getCanonicalName());
         }

         SensitiveValuesProvider provider = (SensitiveValuesProvider)clazz.getConstructor().newInstance();
         provider.initialize(fileLocationResolver, allProperties);
         return provider;
      } else {
         throw new IllegalArgumentException("Cannot load sensitive values provider: property sensitive-values-provider is not defined");
      }
   }

   private static String getProviderClassName(Properties properties, Consumer<String> logger) {
      String className = properties.getProperty("sensitive-values-provider");
      if ("ch.ergon.iam.sensitive.JceksSensitiveValuesProvider".equals(className)) {
         logger.accept("WARNING: the sensitive value provider configuration should be changed to " + JceksSensitiveValuesProvider.class.getCanonicalName());
         return JceksSensitiveValuesProvider.class.getCanonicalName();
      } else {
         return className;
      }
   }
}
