package net.northking.cctp.se.debugger;

import net.northking.cctp.se.dto.ATULog;
import net.northking.cctp.se.exec.ATUScriptInstance;
import net.northking.cctp.se.script.ATUScript;
import net.northking.cctp.se.script.ScriptStep;
import net.northking.cctp.se.script.ScriptVariable;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

public abstract class ATUDebuggerLifecycle<T> implements AutomationTestDebugger<T>
{
  /**
   * 调试器ID
   */
  protected String id;

  protected T nativeClient;

  protected boolean closed = false;

  public ATUDebuggerLifecycle(String id, T nativeClient)
  {
    this.id = id;
    this.nativeClient = nativeClient;
  }

  @Override
  public void setNativeClient(T nativeClient)
  {
    this.nativeClient = nativeClient;
  }

  public String getId()
  {
    return id;
  }

  public void setId(String id)
  {
    this.id = id;
  }

  @Override
  public void close()
  {
    closed = true;
  }

  @Override
  public boolean isClosed()
  {
    return closed;
  }


  /**
   * 执行标志，判断是否正在执行
   */
  private AtomicBoolean flagStart = new AtomicBoolean(false);


  /**
   * 停止回放的标志
   */
  protected AtomicBoolean flagStop = new AtomicBoolean(false);


  public boolean isStarting()
  {
    return flagStart.get();
  }

  public boolean isStopped()
  {
    return !isStarting();
  }

  @Override
  public void stop()
  {
    flagStop.set(true);
  }

  /**
   * 重启浏览器回放脚本
   */
  public static final String REPLAY_RESTART = "restart";

  /**
   * 从头开始回放脚本
   */
  public static final String REPLAY_ALL = "all";

  /**
   * 从指定步骤开始回放脚本
   */
  public static final String REPLAY_FROM = "from";

  /**
   * 单步回放
   */
  public static final String REPLAY_STEP = "step";

  /**
   * 回放方式
   *
   * @return 回放方式
   */
  public abstract String getReplayType();

  /**
   * 指定步骤ID
   *
   * @return 指定步骤ID
   */
  public abstract String targetStepId();

  /**
   * 脚本
   *
   * @return 脚本
   */
  public abstract ATUScript getScript();

  /**
   * TODO 解析脚本
   */
  protected ATUScriptInstance analyseScript()
  {
    ReplayByStep.set(false);
    ATUScriptInstance scriptInstance = new ATUScriptInstance();
    ATUScript script = this.getScript();
    scriptInstance.setCommands(script.getCommands());
    List<ScriptVariable> variables = script.getVariables();
    Map<String, ScriptVariable> variableMap = variables.stream()
            .collect(Collectors.toMap(ScriptVariable::getName, variable -> variable));
    scriptInstance.setVariableMap(variableMap);
    scriptInstance.setGlobalSettings(script.getGlobalSettings());
    scriptInstance.setId(script.getId());
    return scriptInstance;
  }

  /**
   * TODO 调试脚本
   */
  protected void debuggerScript(ATUScriptInstance scriptInstance)
  {
    for (ScriptStep scriptStep : scriptInstance.getCommands())
    {
      // 遍历步骤，执行！~
      if (scriptStep.isSkip()) {  // 注释则不执行
        continue;
      }
      debuggerScriptStep(scriptInstance, scriptStep);
    }
  }

  /**
   * 是否开始执行
   */
  private AtomicBoolean ReplayByStep = new AtomicBoolean(false);

  /**
   * 调试脚本步骤
   *
   * @param scriptStep 脚本步骤
   */
  protected void debuggerScriptStep(ATUScriptInstance scriptInstance, ScriptStep scriptStep)
  {
    if (!ReplayByStep.get() && scriptStep.getId().equals(targetStepId()))
    {
      // 找到指定的步骤，从此开始回放
      ReplayByStep.set(true);
    }

    if (ReplayByStep.get())
    {// 开始回放脚本的步骤
      replayScriptStep(scriptInstance, scriptStep);
    } else
    {// 遍历叶子步骤，递归查找
      for (ScriptStep child : scriptStep.getChildren())
      {
        debuggerScriptStep(scriptInstance, child);
      }
    }
  }

  /**
   * TODO 回放脚本步骤
   *
   * @param scriptInstance 脚本实例
   * @param scriptStep     脚本步骤
   */
  protected void replayScriptStep(ATUScriptInstance scriptInstance, ScriptStep scriptStep)
  {
    beforeReplayScriptStep(scriptStep);
    Object stepResult = null;

      ATUScript subScript; // 被调用的脚本
      ATUScriptInstance subScriptInstance = new ATUScriptInstance(); // 被调用的脚本实例
      executeScript(subScriptInstance);
    afterReplayScriptStep(scriptStep, stepResult);
  }

  /**
   * 回放脚本步骤的前置处理(脚本里的每一个步骤)
   */
  protected abstract void beforeReplayScriptStep(ScriptStep scriptStep);

  /**
   * 回放脚本步骤的后置处理(脚本里的每一个步骤)
   */
  protected abstract void afterReplayScriptStep(ScriptStep scriptStep, Object stepResult);

  /**
   * 记录日志
   */
  protected abstract void logger(ATULog atuLog);

  /**
   * TODO 执行脚本实例
   *
   * @param scriptInstance 脚本实例
   */
  protected void executeScript(ATUScriptInstance scriptInstance)
  {

  }

  /**
   * TODO 执行业务组件
   *
   * @param scriptInstance 脚本实例
   * @param bizComponent   业务组件
   */
  protected void executeBizComponent(ATUScriptInstance scriptInstance, Object bizComponent)
  {

  }

  /**
   * TODO 执行基础组件
   *
   * @param scriptInstance 脚本实例
   * @param component      基础组件
   */
  protected void executeBasicComponent(ATUScriptInstance scriptInstance, Object component)
  {

  }


}
