package com.hubspot.jinjava.interpret;

import static org.assertj.core.api.Assertions.assertThat;

import org.junit.Before;
import org.junit.Test;

import com.hubspot.jinjava.Jinjava;
import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.random.RandomNumberGeneratorStrategy;

public class DeferredTest {

  private JinjavaInterpreter interpreter;

  @Before
  public void setup() {
    Jinjava jinjava = new Jinjava();

    Context context = new Context();
    JinjavaConfig config = JinjavaConfig.newBuilder()
        .withRandomNumberGeneratorStrategy(RandomNumberGeneratorStrategy.DEFERRED)
        .build();
    interpreter = new JinjavaInterpreter(jinjava, context, config);
    interpreter.getContext().put("deferred", DeferredValue.instance());
    interpreter.getContext().put("resolved", "resolvedValue");
  }

  @Test
  public void checkAssumptions() {
    // Just checking assumptions
    String output = interpreter.render("deferred");
    assertThat(output).isEqualTo("deferred");

    output = interpreter.render("resolved");
    assertThat(output).isEqualTo("resolved");

    output = interpreter.render("a {{resolved}} b");
    assertThat(output).isEqualTo("a resolvedValue b");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itDefersSimpleExpressions() {
    String output = interpreter.render("a {{deferred}} b");
    assertThat(output).isEqualTo("a {{deferred}} b");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itDefersWholeNestedExpressions() {
    String output = interpreter.render("a {{deferred.nested}} b");
    assertThat(output).isEqualTo("a {{deferred.nested}} b");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itDefersAsLittleAsPossible() {
    String output = interpreter.render("a {{deferred}} {{resolved}} b");
    assertThat(output).isEqualTo("a {{deferred}} resolvedValue b");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesIfTag() {
    String output = interpreter.render("{% if deferred %}{{resolved}}{% else %}b{% endif %}");
    assertThat(output).isEqualTo("{% if deferred %}{{resolved}}{% else %}b{% endif %}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  /**
   * This may or may not be desirable behaviour.
   */
  @Test
  public void itDoesntPreservesElseIfTag() {
    String output = interpreter.render("{% if true %}a{% elif deferred %}b{% endif %}");
    assertThat(output).isEqualTo("a");
    assertThat(interpreter.getErrors()).isEmpty();
  }

 @Test
  public void itResolvesIfTagWherePossible() {
   String output = interpreter.render("{% if true %}{{deferred}}{% endif %}");
   assertThat(output).isEqualTo("{{deferred}}");
   assertThat(interpreter.getErrors()).isEmpty();
 }

  @Test
  public void itResolvesForTagWherePossible() {
    String output = interpreter.render("{% for i in [1, 2] %}{{i}}{{deferred}}{% endfor %}");
    assertThat(output).isEqualTo("1{{deferred}}2{{deferred}}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesNestedExpressions() {
    interpreter.getContext().put("nested", "some {{deferred}} value");
    String output = interpreter.render("Test {{nested}}");
    assertThat(output).isEqualTo("Test some {{deferred}} value");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesForTag() {
    String output = interpreter.render("{% for item in deferred %}{{item.name}}{% else %}last{% endfor %}");
    assertThat(output).isEqualTo("{% for item in deferred %}{{item.name}}{% else %}last{% endfor %}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesFilters() {
    String output = interpreter.render("{{ deferred|capitalize }}");
    assertThat(output).isEqualTo("{{ deferred|capitalize }}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesFunctions() {
    String output = interpreter.render("{{ deferred|datetimeformat('%B %e, %Y') }}");
    assertThat(output).isEqualTo("{{ deferred|datetimeformat('%B %e, %Y') }}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

  @Test
  public void itPreservesRandomness() {
    String output = interpreter.render("{{ [1,2,3]|shuffle }}");
    assertThat(output).isEqualTo("{{ [1,2,3]|shuffle }}");
    assertThat(interpreter.getErrors()).isEmpty();
  }

}

@@ -2256,16 +2256,361 @@
 );%0A  %7D%0A%0A
+  @Test%0A  public void itPreservesNestedIfTag() %7B%0A    String output = interpreter.render(%22%7B%25 if deferred %25%7D%7B%25 if resolved %25%7D%7B%7Bresolved%7D%7D%7B%25 endif %25%7D%7B%25 else %25%7Db%7B%25 endif %25%7D%22);%0A    assertThat(output).isEqualTo(%22%7B%25 if deferred %25%7D%7B%25 if resolved %25%7D%7B%7Bresolved%7D%7D%7B%25 endif %25%7D%7B%25 else %25%7Db%7B%25 endif %25%7D%22);%0A    assertThat(interpreter.getErrors()).isEmpty();%0A  %7D%0A%0A
   /**%0A  

Test reconstructImage for nested tag nodes