package com.oguerreiro.resilient.expression;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * Base functions
 */
public class BaseExpressionFunctions implements ExpressionFunctions {

  private ThreadLocal<Boolean> traceEnabled = ThreadLocal.withInitial(() -> Boolean.FALSE);
  private ThreadLocal<List<String>> trace;

  public void error(String message) {
    throw new RuntimeException(message);
  }

  protected BigDecimal safeBigDecimal(BigDecimal value) {
    if (value == null) {
      return BigDecimal.ZERO;
    }
    return value;
  }

  public final Boolean isTraceEnabled() {
    return this.traceEnabled.get();
  }

  public final void enableTrace() {
    this.traceEnabled.set(Boolean.TRUE);
    this.trace.set(new ArrayList<String>());
  }

  public final List<String> stopTrace() {
    this.traceEnabled.set(Boolean.FALSE);
    List<String> myTrace = this.trace.get();
    this.trace.set(null);

    return myTrace;
  }

  public final void addTrace(String function, String warn, Object result, Object... args) {
    if (this.isTraceEnabled()) {
      StringBuilder functionCall = new StringBuilder();

      // Function call signature: in('010101', 'xpto')
      functionCall.append(function).append("(");
      boolean isFirst = true;
      for (Object object : args) {
        if (!isFirst)
          functionCall.append(" , ");

        functionCall.append(traceValue(object));

        isFirst = false;
      }
      functionCall.append(")");

      // Function result: = 0,9876
      functionCall.append("=").append(traceValue(result));

      // Function warning: *WARN: warning text
      if (warn != null && !warn.isBlank()) {
        functionCall.append(" *WARN: ").append(warn);
      }

      this.trace.get().add(functionCall.toString());
    }
  }

  private String traceValue(Object value) {
    if (value instanceof String) {
      return "'" + value.toString() + "'";
    } else {
      return value.toString();
    }
  }
}
