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

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.plugin.api.config.LogTypes;
import com.airlock.iam.plugin.framework.application.service.ConfigReader;
import com.airlock.iam.plugin.framework.domain.model.MedusaConfigurationElement;
import com.airlock.iam.plugin.framework.infrastructure.yaml.importer.YamlConfigurationParser;
import com.airlock.iam.system.config.YamlLoaderFactory;
import com.airlock.iam.system.version.IamVersion;
import java.io.InputStream;
import java.util.Map;
import java.util.Optional;
import org.snakeyaml.engine.v2.exceptions.YamlEngineException;

public class YamlConfigReader implements ConfigReader {
   private static final ELogger LOG = ELoggerFactory.getLogger(YamlConfigReader.class);

   @Override
   public MedusaConfigurationElement read(InputStream input) throws ConfigReader.ConfigLoaderException {
      Map<?, ?> configMap = readToMap(input);
      YamlConfigurationParser parser = new YamlConfigurationParser(tryRetrieveIamVersion(configMap));
      return parser.parseToConfigurationElement(configMap);
   }

   public static Map<?, ?> readToMap(InputStream input) throws ConfigReader.ConfigLoaderException {
      Object configObject;
      try {
         configObject = YamlLoaderFactory.loadFromInputStream(input);
      } catch (YamlEngineException e) {
         LOG.warn(LogTypes.CONFIGURATION_ERROR, "Error parsing configuration file: " + e.getMessage());
         throw new ConfigReader.ConfigLoaderException("Invalid YAML configuration: " + e.getMessage(), e);
      }

      if (configObject instanceof Map<?, ?> configMap) {
         return configMap;
      } else {
         throw new ConfigReader.ConfigLoaderException("Invalid YAML configuration, top-level element must be a map");
      }
   }

   private static IamVersion tryRetrieveIamVersion(Map<?, ?> configMap) throws ConfigReader.ConfigLoaderException {
      try {
         return Optional.ofNullable(configMap.get("metadata"))
            .map(metadata -> ((Map)metadata).get("iamVersion"))
            .map(version -> IamVersion.fromString((String)version))
            .orElseThrow(() -> new ConfigReader.ConfigLoaderException("No IAM version present within the YAML configuration."));
      } catch (ClassCastException e) {
         throw new ConfigReader.ConfigLoaderException("IAM version cannot be accessed due to structural errors in the YAML configuration.", e);
      } catch (IllegalArgumentException e) {
         throw new ConfigReader.ConfigLoaderException("IAM version is not valid: " + e.getMessage());
      }
   }
}
