package com.hubspot.jinjava.objects.serialization;

import com.fasterxml.jackson.core.JsonFactoryBuilder;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.interpret.OutputTooBigException;
import com.hubspot.jinjava.util.WhitespaceUtils;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;

public class PyishObjectMapper {
  public static final ObjectWriter PYISH_OBJECT_WRITER;

  static {
    ObjectMapper mapper = new ObjectMapper(
      new JsonFactoryBuilder().quoteChar('\'').build()
    )
    .registerModule(
        new SimpleModule()
          .setSerializerModifier(PyishBeanSerializerModifier.INSTANCE)
          .addSerializer(PyishSerializable.class, PyishSerializer.INSTANCE)
      );
    mapper.getSerializerProvider().setNullKeySerializer(new NullKeySerializer());
    PYISH_OBJECT_WRITER =
      mapper.writer(PyishPrettyPrinter.INSTANCE).with(PyishCharacterEscapes.INSTANCE);
  }

  public static String getAsUnquotedPyishString(Object val) {
    if (val != null) {
      return WhitespaceUtils.unquoteAndUnescape(getAsPyishString(val));
    }
    return "";
  }

  public static String getAsPyishString(Object val) {
    try {
      return getAsPyishStringOrThrow(val);
    } catch (JsonProcessingException e) {
      return Objects.toString(val, "");
    }
  }

  public static String getAsPyishStringOrThrow(Object val)
    throws JsonProcessingException {
    String string = PYISH_OBJECT_WRITER.writeValueAsString(val);
    Optional<Long> maxStringLength = JinjavaInterpreter
      .getCurrentMaybe()
      .map(interpreter -> interpreter.getConfig().getMaxStringLength())
      .filter(max -> max > 0);
    if (maxStringLength.map(max -> string.length() > max).orElse(false)) {
      throw new OutputTooBigException(maxStringLength.get(), string.length());
    }
    if (string.contains("}}") && !string.contains("{{")) {
      return String.join("} ", string.split("}(?=})"));
    }
    return string;
  }

  public static class NullKeySerializer extends JsonSerializer<Object> {

    @Override
    public void serialize(
      Object o,
      JsonGenerator jsonGenerator,
      SerializerProvider serializerProvider
    )
      throws IOException {
      jsonGenerator.writeFieldName("");
    }
  }
}

@@ -1901,75 +1901,138 @@
 nal%3C
-Long%3E maxStringLength = JinjavaInterpreter%0A      .getCurrent
+JinjavaInterpreter%3E interpreterMaybe = JinjavaInterpreter.getCurrentMaybe();%0A    Optional%3CLong%3E maxStringLength = interpreter
 Maybe
-()
 %0A   
@@ -2299,16 +2299,273 @@
     if (
+%0A      interpreterMaybe%0A        .map(%0A          interpreter -%3E%0A            interpreter%0A              .getConfig()%0A              .getTokenScannerSymbols()%0A              .getExpressionEnd()%0A              .equals(%22%7D%7D%22)%0A        )%0A        .orElse(true) &&%0A      
 string.c
@@ -2580,16 +2580,22 @@
 %22%7D%7D%22) &&
+%0A     
  !string
@@ -2609,16 +2609,21 @@
 ns(%22%7B%7B%22)
+%0A    
 ) %7B%0A    

Check that the expression end token is `}}` before splitting the curly braces