package io.delphi.qa.auto.awsmfrw.tests.poc;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import com.google.common.base.CaseFormat;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaCommonMethods;
import io.delphi.qa.auto.awsmfrw.models.EnDelphiDspItems;
import io.delphi.qa.auto.awsmfrw.models.api.ICanBuildApiTestByString;
import org.apache.commons.lang3.ArrayUtils;
import org.testng.annotations.Test;
import org.testng.collections.Sets;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

public class TestCsvParsing {

  public Set<String> structureQueryParams =
      Sets.newHashSet("sort_by", "sort_order", "group_by", "include", "is_assigned", "is_pending");

  @Test
  public void processTsv0DelphiApiLogs2PerfPatterns0Csv() throws IOException {
    //    String inputFile = "src/test/resources/extract.csv";
    String inputFile = "src/test/resources/input.tsv";
    CsvSchema schema =
        CsvSchema.emptySchema()
            .withHeader()
            .withUseHeader(true)
            .withColumnSeparator('\t')
            .withArrayElementSeparator("\",\"");
    ObjectMapper mapper =
        new CsvMapper().enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    MappingIterator<HashMap> logs =
        mapper.readerFor(HashMap.class).with(schema).readValues(new File(inputFile));
    List<HashMap> mlDelphiApiLogs = logs.readAll();
    String outputFile = "src/test/resources/output.tsv";
    mapper
        .writer(schema.withUseHeader(false).withColumnSeparator('\n'))
        .writeValue(
            new File(outputFile),
            mlDelphiApiLogs.stream().map(this::buildPerfPattern).collect(Collectors.toSet()));
  }

  private Object buildPerfPattern(HashMap<String, String> map) {
    String basePattern =
        String.format(
            "%s{assert}%s{method}%s{path}{query}",
            ICanBuildApiTestByString.STR_ASSERT_MARKER,
            ICanBuildApiTestByString.STR_METHOD_MARKER,
            ICanBuildApiTestByString.STR_PATH_MARKER);
    String queryParamsPattern =
        String.format("%s{query_params}", ICanBuildApiTestByString.STR_QUERY_MARKER);
    Map<String, String> param =
        map.entrySet().stream()
            .filter(item -> item.getKey().startsWith("extra.params."))
            .collect(
                Collectors.toMap(x -> x.getKey().replace("extra.params.", ""), x -> x.getValue()));
    String tokensToString =
        param.entrySet().stream()
            .filter(x -> !"".equals(x.getValue()))
            .map(
                x -> {
                  String queryParamPattern = "%s%s%s";
                  String key = x.getKey();
                  String queryParamName =
                      CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, key);
                  String queryParamValue =
                      CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, key);
                  // Case: query param value is List
                  if (x.getValue().split(",").length > 1) {
                    queryParamPattern += 's';
                  } else
                  // Case: query param value contains dot sign
                  if (structureQueryParams.stream()
                      .anyMatch(
                          sqp -> sqp.equals(x.getKey()))) {
                    String structureQueryParam =
                        x.getValue()
                            .replace("[\"", "")
                            .replace("\"]", "")
                            .replace(".", ICanBuildApiTestByString.STR_UNDERSCORE_MARKER);
                    queryParamValue =
                        CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, structureQueryParam);
                  }
                  return String.format(
                      queryParamPattern,
                      queryParamName,
                      ICanBuildApiTestByString.STR_EQUAL_MARKER,
                      queryParamValue);
                })
            .filter(Objects::nonNull)
            .collect(Collectors.joining("_"));
    String queryParamPatternFilled =
        IsaCommonMethods.resolvePattern(
            queryParamsPattern,
            new HashMap<String, String>() {
              {
                put("query_params", tokensToString);
              }
            });
    String pattern =
        IsaCommonMethods.resolvePattern(
            basePattern,
            new HashMap<String, String>() {
              {
                put("assert", "Sc200");
                put(
                    "method",
                    CaseFormat.LOWER_UNDERSCORE.to(
                        CaseFormat.UPPER_CAMEL, map.get("extra.method")));
                String value = tokenizePath(map.get("extra.path"));
                put("path", value);
                put(
                    "query",
                    !ICanBuildApiTestByString.STR_QUERY_MARKER.equals(queryParamPatternFilled)
                        ? queryParamPatternFilled
                        : "");
              }
            });
    return pattern;
  }

  private String tokenizePath(String path) {
    String to =
        path.split("v3/")[1].replace(
            "-", String.format("_%s_", ICanBuildApiTestByString.STR_DASH_PARAM_MARKER));
    to = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, to).replace("_", "");
    String[] strings = to.split("/");
    String s = null;
    if (strings.length > 1) {
      String[] finalStrings = strings;
      boolean present =
          Arrays.stream(EnDelphiDspItems.values())
              .anyMatch(
                  o ->
                      finalStrings[1]
                          .toLowerCase(Locale.ROOT)
                          .startsWith(o.name().toLowerCase(Locale.ROOT)));
      if (present) {
        String str = strings[0].substring(0, strings[0].length() - 1) + "_id";
        strings[1] =
            strings[0]
                + ICanBuildApiTestByString.STR_PATH_PARAM_MARKER
                + CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, str);
        strings = ArrayUtils.remove(strings, 0);
      }
    }
    String collect =
        Arrays.stream(strings)
            .map(o -> CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, o))
            .collect(Collectors.joining(ICanBuildApiTestByString.STR_PATH_SLASH_MARKER));
    return collect;
  }
}
