package com.outbrain.gomjabbar.faults;

import com.outbrain.gomjabbar.execution.CommandExecutor;
import com.outbrain.gomjabbar.execution.RemoteCommand;
import com.outbrain.gomjabbar.targets.Target;
import com.outbrain.ob1k.concurrent.ComposableFuture;
import com.outbrain.ob1k.concurrent.ComposableFutures;
import org.apache.commons.lang.text.StrSubstitutor;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * A configurable (shell) fault command injector.
 * @author Eran Harel
 */
public class FaultCommandInjector implements FaultInjector {

  private final CommandExecutor commandExecutor;
  private final FaultCommand faultCommand;

  FaultCommandInjector(final CommandExecutor commandExecutor, final FaultCommand faultCommand) {
    this.commandExecutor = Objects.requireNonNull(commandExecutor, "commandExecutor must not be null");
    this.faultCommand = Objects.requireNonNull(faultCommand, "faultCommand must not be null");
  }

  @Override
  public String id() {
    return faultCommand.id;
  }

  @Override
  public String description() {
    return faultCommand.description;
  }

  @Override
  public ComposableFuture<String> injectFailure(final Target target) {
    return execute(target, faultCommand.command);
  }

  @Override
  public ComposableFuture<String> revertFailure(final Target target) {
    return faultCommand.revertCommand == null ?
      ComposableFutures.fromValue("no revert script was provided") :
      execute(target, faultCommand.revertCommand);
  }

  private ComposableFuture<String> execute(final Target target, final String command) {
    final RemoteCommand remoteCommand = RemoteCommand.Builder.forTarget(target.getHost()).buildCommand(formatCommand(command, target));
    return commandExecutor.executeCommandAsync(remoteCommand);
  }

  private String formatCommand(final String command, final Target target) {
    Map<Object, Object> valuesMap = new HashMap<>();
    valuesMap.put("host", target.getHost());
    valuesMap.put("module", target.getModule());
    valuesMap.putAll(System.getProperties());

    return new StrSubstitutor(valuesMap).replace(command);
  }

}