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

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.services.stepfunctions.AWSStepFunctions;
import com.amazonaws.services.stepfunctions.AWSStepFunctionsClientBuilder;
import com.amazonaws.services.stepfunctions.model.*;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaCommonMethods;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaLogging;
import io.qameta.allure.Step;

import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class HlAwsStepFunctions extends BsAwsSdkV1 {

  private AWSStepFunctions client;
  private HlAwsSfAssertions assertions;

  public HlAwsStepFunctions() {
    client = AWSStepFunctionsClientBuilder.standard().withRegion(region).build();
  }

  public HlAwsSfAssertions asserts() {
    return assertions == null ? assertions = new HlAwsSfAssertions() : assertions;
  }

  @Step("AWS::StepFunctions: list events(execution history)")
  public List<HistoryEvent> listEvents(
      String flow, String stateMachineName, String tillStatusEquals) {
    StateMachineListItem stateMachine = this.getStateMachine(flow);
    ExecutionListItem executionListItem =
        this.getExecutionListItemByArn(stateMachine, stateMachineName);
    GetExecutionHistoryRequest getExecutionHistoryRequest =
        new GetExecutionHistoryRequest().withExecutionArn(executionListItem.getExecutionArn());
    while (this.getExecutionListItemByArn(stateMachine, stateMachineName)
        .getStatus()
        .equals(tillStatusEquals)) {
      IsaCommonMethods.aWait(30, TimeUnit.SECONDS, 1);
    }
    IsaCommonMethods.aWait(10, TimeUnit.SECONDS, 1);
    return client.getExecutionHistory(getExecutionHistoryRequest).getEvents();
  }

  @Deprecated
  @Step("AWS::StepFunctions: match events(execution history)")
  public List<HistoryEvent> matchEvents(
      String flow, String stateMachinePrefix, String tillStatusEquals) {
    StateMachineListItem stateMachine =
        this.getStateMachine(flow);
    ListExecutionsResult listExecutionsResult =
        this.getListExecutionsResult(stateMachine);
    List<ExecutionListItem> collect =
        listExecutionsResult.getExecutions().stream()
            .filter(o -> o.getName().startsWith(stateMachinePrefix))
            .sorted(Comparator.comparing(ExecutionListItem::getStartDate).reversed())
            .collect(Collectors.toList());
    ExecutionListItem executionListItem =
        this.getExecutionListItemByArn(stateMachine, collect.get(0).getName());
    GetExecutionHistoryRequest getExecutionHistoryRequest =
        new GetExecutionHistoryRequest().withExecutionArn(executionListItem.getExecutionArn());
    List<HistoryEvent> historyEventList =
        //        this.getClient().getExecutionHistory(getExecutionHistoryRequest).getEvents();
        client.getExecutionHistory(getExecutionHistoryRequest).getEvents();
    while (this.getExecutionListItemByArn(stateMachine,  collect.get(0).getName())
        .getStatus()
        .equals(tillStatusEquals)) {
      IsaCommonMethods.aWait(30, TimeUnit.SECONDS, 1);
      historyEventList =
          //          this.getClient().getExecutionHistory(getExecutionHistoryRequest).getEvents();
          client.getExecutionHistory(getExecutionHistoryRequest).getEvents();
    }
    return historyEventList;
  }

  @Deprecated
  public AWSStepFunctions getClient() {
    return client;
  }

  @Step("AWS::StepFunctions: get state_machine by flow")
  public StateMachineListItem getStateMachine(String flow) {
    StringBuilder msg = new StringBuilder("\nAWS::StepFunctions: get state_machine by flow:");
    msg.append("\n- flow:").append(flow);
    try {
      ListStateMachinesResult listStateMachinesResult =
          client.listStateMachines(new ListStateMachinesRequest());
      List<StateMachineListItem> stateMachines = listStateMachinesResult.getStateMachines();
      StateMachineListItem stateMachineListItem =
          stateMachines.stream()
              .filter(i -> i.getName().endsWith(flow))
              .collect(Collectors.toList())
              .get(0);
      msg.append("\n- state machine:\n").append(gson.toJson(stateMachineListItem));
      return stateMachineListItem;
    } catch (AmazonServiceException e) {
      msg.append(
          "\n- exception: Caught an AmazonServiceException, which means"
              + " your request made it to Amazon Step Functions, but was"
              + " rejected with an error response for some reason.");
      throw e;
    } catch (AmazonClientException e) {
      msg.append(
          "\n- exception: Caught an AmazonClientException, which means "
              + "the client encountered a serious internal problem while "
              + "trying to communicate with Step Functions, such as not "
              + "being able to access the network.");
      throw e;
    } finally {
      IsaLogging.log(this.getClass(), String.valueOf(msg));
    }
  }

  @Step("AWS::StepFunctions: list all state_machines")
  public ListStateMachinesResult getListStateMachinesResult() {
    return client.listStateMachines(new ListStateMachinesRequest());
  }

  @Step("AWS::StepFunctions: list all executions")
  public ListExecutionsResult getListExecutionsResult(StateMachineListItem sm) {
    ListExecutionsRequest listRequest =
        new ListExecutionsRequest().withStateMachineArn(sm.getStateMachineArn());
    ListExecutionsResult listExecutionsResult = client.listExecutions(listRequest);
    while (listExecutionsResult == null) {
      listExecutionsResult = client.listExecutions(listRequest);
    }
    return listExecutionsResult;
  }

  @Step("AWS::StepFunctions: get execution by ARN")
  public ExecutionListItem getExecutionListItemByArn(
      StateMachineListItem stateMachine, String sfName) {
    StringBuilder msg = new StringBuilder("\nAWS::StepFunctions: get execution by ARN");
    List<ExecutionListItem> executionListItemList =
        getListExecutionsResult(stateMachine).getExecutions();
    ExecutionListItem executionListItem =
        executionListItemList.stream()
            .filter(o -> o.getName().equals(sfName))
            .findFirst()
            .orElse(new ExecutionListItem());
    msg.append("\n- name: ").append(executionListItem.getName());
    msg.append("\n- arn: ").append(executionListItem.getStateMachineArn());
    IsaLogging.log(this.getClass(), String.valueOf(msg));
    return executionListItem;
  }

  @Step("AWS::StepFunctions: get task result")
  public GetActivityTaskResult getActivityTaskResult(String activityArn) {
    return client.getActivityTask(new GetActivityTaskRequest().withActivityArn(activityArn));
  }

}
