package com.airlock.iam.plugin.framework.infrastructure.io;

import com.airlock.iam.base.api.domain.model.exception.FailureException;
import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.exception.InitializeException;
import com.airlock.iam.plugin.framework.application.service.ConfigLocationResolver;
import com.airlock.iam.plugin.framework.application.service.ConfigReader;
import com.airlock.iam.plugin.framework.application.service.TranslatedConfigReader;
import com.airlock.iam.plugin.framework.domain.model.MedusaConfiguration;
import com.airlock.iam.plugin.framework.domain.model.MedusaConfigurationElement;
import com.airlock.iam.plugin.framework.misc.config.ConfigHistoryItem;
import com.airlock.iam.plugin.framework.misc.frompersistence.PersistenceModelToPCModelTranslation;
import com.airlock.iam.plugin.framework.misc.frompersistence.TranslatedMedusaConfiguration;
import com.google.common.base.Preconditions;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;

public class NewTranslatedConfigModelToLegacyReader implements TranslatedConfigReader {
   private static final ELogger LOG = ELoggerFactory.getLogger(NewTranslatedConfigModelToLegacyReader.class);
   private final PersistenceModelToPCModelTranslation translator;
   private final ConfigReader reader;
   private ConfigLocationResolver locationResolver;

   public NewTranslatedConfigModelToLegacyReader(PersistenceModelToPCModelTranslation translator, ConfigReader reader, ConfigLocationResolver locationResolver) {
      this.translator = (PersistenceModelToPCModelTranslation)Preconditions.checkNotNull(translator);
      this.reader = (ConfigReader)Preconditions.checkNotNull(reader);
      this.locationResolver = (ConfigLocationResolver)Preconditions.checkNotNull(locationResolver);
   }

   @Override
   public TranslatedMedusaConfiguration loadConfig(File configFile) throws InitializeException {
      Preconditions.checkNotNull(configFile);
      MedusaConfigurationElement configElement = this.readConfigElementFromFile(configFile);
      return this.translateMedusaConfiguration(configElement);
   }

   @Override
   public TranslatedMedusaConfiguration loadConfig(InputStream xmlConfig) throws InitializeException {
      Preconditions.checkNotNull(xmlConfig);
      MedusaConfigurationElement configElement = this.readConfigElement(xmlConfig);
      return this.translateMedusaConfiguration(configElement);
   }

   private TranslatedMedusaConfiguration translateMedusaConfiguration(MedusaConfigurationElement configElement) throws InitializeException {
      try {
         MedusaConfiguration config = this.createConfigFromConfigElement(configElement);
         return this.translator.translate(config);
      } catch (PersistenceModelToPCModelTranslation.PersistenceModelToPCModelTranslationException e) {
         throw new InitializeException("Translation from persistency model to plugin configuration model failed: " + e.getMessage(), e);
      }
   }

   private MedusaConfigurationElement readConfigElement(InputStream xmlConfig) throws InitializeException {
      try {
         return this.reader.read(xmlConfig);
      } catch (ConfigReader.ConfigLoaderException e) {
         throw new InitializeException("Unable to read the configuration: " + e.getMessage());
      }
   }

   @Override
   public List<ConfigHistoryItem> loadConfigHistory(File configFile) throws InitializeException {
      Preconditions.checkNotNull(configFile);
      TranslatedMedusaConfiguration config = this.loadConfig(configFile);
      return config.getHistory();
   }

   @Override
   public void registerConfigLocationResolver(ConfigLocationResolver resolver) {
      this.locationResolver = resolver;
   }

   private MedusaConfiguration createConfigFromConfigElement(MedusaConfigurationElement configElement) {
      return new MedusaConfiguration(configElement);
   }

   private MedusaConfigurationElement readConfigElementFromFile(File configFile) throws InitializeException {
      try (InputStream inputStream = Files.newInputStream(this.resolveConfigFileLocation(configFile).toPath())) {
         return this.reader.read(inputStream);
      } catch (FileNotFoundException e) {
         LOG.info("Configuration file to load was not found:" + configFile.getAbsolutePath(), e);
         throw new InitializeException("Configuration file to load was not found: " + configFile.getAbsolutePath(), e);
      } catch (FailureException | ConfigReader.ConfigLoaderException e) {
         throw new InitializeException("Unable to load the configuration from file: " + configFile.getName() + ": " + e.getMessage(), e);
      } catch (IOException e) {
         throw new InitializeException("Failed to read configuration file: " + configFile.getName() + ": " + e.getMessage(), e);
      }
   }

   private File resolveConfigFileLocation(File configFile) throws IOException {
      return this.locationResolver.resolve(configFile.getPath()).toFile();
   }
}
