package com.airlock.iam.base.misc.message;

import com.airlock.iam.elog.api.ELogger;
import com.airlock.iam.elog.api.ELoggerFactory;
import com.airlock.iam.elog.api.LogTypes;
import java.text.Format;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.ExtendedMessageFormat;
import org.apache.commons.text.FormatFactory;

public class GrowableMessageFormat {
   private static final Map<String, FormatFactory> FORMAT_MAP = new HashMap<>();
   private static final ELogger LOG = ELoggerFactory.getLogger(GrowableMessageFormat.class);
   private final ExtendedMessageFormat messageFormat;
   private final int maxAllowedStringLength;

   public GrowableMessageFormat(String pattern, int maxLength) {
      this.messageFormat = new ExtendedMessageFormat(pattern, FORMAT_MAP);
      this.maxAllowedStringLength = maxLength;
   }

   public Optional<String> formatMaximalString(Object[] arguments) {
      String currentMessage = StringUtils.trim(this.messageFormat.format(arguments));
      if (currentMessage.length() > this.maxAllowedStringLength) {
         LOG.warn(
            LogTypes.CONFIGURATION_ERROR,
            "Minimal possible size of pattern \""
               + this.messageFormat.toPattern()
               + "\" ("
               + currentMessage.length()
               + ") longer than allowed maximum length: "
               + this.maxAllowedStringLength
         );
         return Optional.empty();
      }

      if (currentMessage.length() == this.maxAllowedStringLength) {
         return Optional.of(currentMessage);
      }

      List<GrowableFormat> growableFormats = new ArrayList<>();

      for (Format f : this.messageFormat.getFormats()) {
         if (f instanceof GrowableFormat gf && gf.canGrow()) {
            growableFormats.add(gf);
         }
      }

      if (growableFormats.isEmpty()) {
         return Optional.of(currentMessage);
      }

      int allowedSizeToGrow = this.maxAllowedStringLength - currentMessage.length();
      int[] growArray = this.divideAllowedSizeToGrowAmongFormats(allowedSizeToGrow, growableFormats.size());

      for (int i = 0; i < growableFormats.size(); i++) {
         growableFormats.get(i).growBy(growArray[i]);
      }

      return this.formatMaximalString(arguments);
   }

   private int[] divideAllowedSizeToGrowAmongFormats(int allowedSizeToGrow, int numberOfGrowableFormats) {
      int sizeToGrowPerFormat = (int)Math.floor((double)allowedSizeToGrow / numberOfGrowableFormats);
      int[] list = new int[numberOfGrowableFormats];
      Arrays.fill(list, sizeToGrowPerFormat);
      int remainder = allowedSizeToGrow % numberOfGrowableFormats;

      for (int i = 0; i < remainder; i++) {
         list[i]++;
      }

      return list;
   }

   static {
      FORMAT_MAP.put("left", GrowableFormatFactory.getInstance());
      FORMAT_MAP.put("right", GrowableFormatFactory.getInstance());
      FORMAT_MAP.put("mid", GrowableFormatFactory.getInstance());
   }
}
