package io.delphi.qa.auto.awsmfrw.managers.helpers.aws;

import com.amazonaws.services.lambda.model.ResourceNotFoundException;
import com.amazonaws.services.secretsmanager.AWSSecretsManager;
import com.amazonaws.services.secretsmanager.AWSSecretsManagerClientBuilder;
import com.amazonaws.services.secretsmanager.model.*;
import com.google.gson.reflect.TypeToken;
import io.delphi.qa.auto.awsmfrw.common_baby.ICanProvideHelpers;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaLogging;
import io.delphi.qa.auto.awsmfrw.suppliers.DelphiDataContainer;
import io.qameta.allure.Allure;
import io.qameta.allure.Step;

import java.security.InvalidParameterException;
import java.util.Base64;
import java.util.Map;

public class HlAwsSecretManager extends BsAwsSdkV1
    implements ICanProvideHelpers<HlAwsSecretManager> {

  private AWSSecretsManager client;

  public HlAwsSecretManager() {
    Allure.step(
        "Init AWS Secret Manager client",
        () -> {
          client = AWSSecretsManagerClientBuilder.standard().withRegion(region).build();
        });
  }

  @Step("AWS::SecretManager: get secret map")
  public Map<String, String> getSecretMap(final String secretName) {
    return decryptedSecret(downloadSecret(secretName));
  }

  @Step("AWS::SecretManager:  decrypt secret")
  private Map<String, String> decryptedSecret(GetSecretValueResult getSecretValueResult) {
    // Decrypts secret using the associated KMS CMK.
    // Depending on whether the secret is a string or binary, one of these fields will be
    // populated.
    String resultSecret;
    if (getSecretValueResult.getSecretString() != null) {
      resultSecret = getSecretValueResult.getSecretString();
    } else {
      resultSecret =
          new String(Base64.getDecoder().decode(getSecretValueResult.getSecretBinary()).array());
    }
    Map<String, String> fromJson =
        gson.fromJson(resultSecret, new TypeToken<Map<String, String>>() {}.getType());
    IsaLogging.log(this.getClass(), "\n- decoded secret\n");
    return fromJson;
  }

  @Step("AWS::SecretManager: download secret")
  private GetSecretValueResult downloadSecret(String secretName) {
    GetSecretValueRequest getSecretValueRequest =
        new GetSecretValueRequest().withSecretId(secretName);
    GetSecretValueResult rsSecret = null;
    IsaLogging.log(this.getClass(), "\n- secret name: " + secretName);
    try {
      rsSecret = client.getSecretValue(getSecretValueRequest);
      IsaLogging.log(this.getClass(), "\n- downloading status: success");
    } catch (DecryptionFailureException e) {
      // Secrets Manager can't decrypt the protected secret text using the provided KMS key.
      // Deal with the exception here, and/or rethrow at your discretion.
      IsaLogging.log(this.getClass(), "\n- downloading status: error:\n\t- exception: " + e);
      throw e;
    } catch (InternalServiceErrorException e) {
      // An error occurred on the server side.
      // Deal with the exception here, and/or rethrow at your discretion.
      IsaLogging.log(this.getClass(), "\n- downloading status: error:\n\t- exception: " + e);
      throw e;
    } catch (InvalidParameterException e) {
      // You provided an invalid value for a parameter.
      // Deal with the exception here, and/or rethrow at your discretion.
      IsaLogging.log(this.getClass(), "\n- downloading status: error:\n\t- exception: " + e);
      throw e;
    } catch (InvalidRequestException e) {
      // You provided a parameter value that is not valid for the current state of the
      // resource.
      // Deal with the exception here, and/or rethrow at your discretion.
      IsaLogging.log(this.getClass(), "\n- downloading status: error:\n\t- exception: " + e);
      throw e;
    } catch (ResourceNotFoundException e) {
      // We can't find the resource that you asked for.
      // Deal with the exception here, and/or rethrow at your discretion.
      IsaLogging.log(this.getClass(), "\n- downloading status: error:\n\t- exception: " + e);
      throw e;
    }
    return rsSecret;
  }

  @Override
  @Step("init client")
  public HlAwsSecretManager init() {
    return this;
  }

  @Override
  @Step("execute query")
  public void query(String context) {
    Map<String, String> secretMap = this.getSecretMap(context);
    DelphiDataContainer.saveResource("AWS_SECRET_RESULT_LOCATOR", secretMap);
  }
}
