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

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Consumer;

public class PlainSecretsSensitiveValuesProvider implements SensitiveValuesProvider {
   private final Path secretsFile;

   public PlainSecretsSensitiveValuesProvider(Path secretsFile) {
      this.secretsFile = secretsFile;
      if (Files.notExists(secretsFile) || !Files.isReadable(secretsFile)) {
         throw new SensitiveValuesProvider.SensitiveValuesProviderException("Secrets file " + secretsFile + " does not exist or is not readable");
      }
   }

   @Override
   public void setSensitiveValue(String key, String value) {
      this.editSecretsFile(secrets -> secrets.put(key, value));
   }

   @Override
   public void deleteSensitiveValue(String key) {
      this.editSecretsFile(secrets -> secrets.remove(key));
   }

   @Override
   public Optional<String> getSensitiveValue(String key) {
      Properties secrets = this.readSecretsFile();
      return Optional.ofNullable(secrets.getProperty(key));
   }

   @Override
   public List<String> getAllDefinedKeys() {
      Properties secrets = this.readSecretsFile();
      return List.copyOf(secrets.stringPropertyNames());
   }

   private void editSecretsFile(Consumer<Properties> edit) {
      Properties secrets = this.readSecretsFile();
      edit.accept(secrets);
      this.writeSecretsFile(secrets);
   }

   private Properties readSecretsFile() {
      Properties properties = new Properties();

      try (Reader reader = Files.newBufferedReader(this.secretsFile, StandardCharsets.UTF_8)) {
         properties.load(reader);
         return properties;
      } catch (IOException e) {
         throw new SensitiveValuesProvider.SensitiveValuesProviderException(e);
      }
   }

   private void writeSecretsFile(Properties secrets) {
      try (Writer writer = Files.newBufferedWriter(this.secretsFile, StandardCharsets.UTF_8)) {
         secrets.store(writer, null);
      } catch (IOException e) {
         throw new SensitiveValuesProvider.SensitiveValuesProviderException(e);
      }
   }
}
