package io.delphi.qa.auto.awsmfrw.managers.helpers.db;

import com.google.common.base.CaseFormat;
import com.google.gson.reflect.TypeToken;
import io.delphi.qa.auto.awsmfrw.common_baby.IsaCommonMethods;
import io.delphi.qa.auto.awsmfrw.models.db.BsSqlTable;
import io.delphi.qa.auto.awsmfrw.models.db.sql.snowflake.BsSnEntity;
import io.qameta.allure.Step;

import java.util.*;
import java.util.stream.Collectors;

public class SnowflakeClient extends BsSnowflake implements IsaCommonMethods {

  private final String STR_SELECT_QUERY_PATTERN = "select\n\t*\nfrom\n\t{table}\n\t{where}";
  private final String STR_SELECT_QUERY_PATTERN_NEW = "select\n\t{fields}\nfrom\n\t{table}\n\t{where}";
  private final String STR_UPDATE_QUERY_PATTERN =
      "update\n"
          + "    {table}\n"
          + "set\n"
          + "    {set}\n"
          + "where\n"
          + "    {where}\n"
          + "returning *;";
  private final String STR_DELETE_QUERY_PATTERN =
      "delete from\n" + "    {table}\n" + "where\n" + "    {where};";
  private final String STR_INSERT_QUERY_PATTERN =
      "insert into\n"
          + "        {table}\n"
          + "        ({columns})\n"
          + "            values\n"
          + "        ({values});";

  public SnowflakeClient(Map<String, String> secretMap) {
    super(secretMap);
  }

  @Step("DB:: do command")
  public String awsmCommand(String queryText) {
    return super.fetchQueryStatus(queryText);
  }

  public List<String> awsmCustomQuery(String queryText) {
    return super.fetchQueriedItems(queryText);
  }

  @Step("DB:: do delete")
  public <T extends BsSnEntity<T>> int awsmDelete(T obj, final String where) {
    HashMap<String, String> params =
        new HashMap<String, String>() {
          {
            put("table", obj.locator());
            put("where", where);
          }
        };
    String queryText = IsaCommonMethods.resolvePattern(STR_DELETE_QUERY_PATTERN, params);
    return super.fetchUpdatedRowsAmount(queryText);
  }

    @Step("Build query:")
    public List<Map<String, String>> awsmQueryNew(String query) {
        return super.queryRows(query);
    }

    @Step("DB:: do insert")
  public <T extends BsSqlTable<T>> List<T> awsmInsert(List<T> set) {
    HashSet<?>[] entity = buildEntity(set);
    String queryText =
        IsaCommonMethods.resolvePattern(
            STR_INSERT_QUERY_PATTERN,
            new HashMap<String, String>() {
              {
                put("table", set.iterator().next().locator());
                put("columns", entity[0].iterator().next().toString());
                String collect =
                    entity[1].stream()
                        .map(Object::toString)
                        .collect(Collectors.joining("),\n\t\t("));
                put("values", collect);
              }
            });
    return super.fetchUpdatedRowsAmount(queryText) == set.size() ? set : null;
  }

  @Step("DB:: do query")
  public <T extends BsSqlTable<T>> List<T> awsmQuery(T obj, String queryText) {
    return super.fetchQueriedEntities(queryText, obj);
  }

  @Step("DB:: do select")
  public <T extends BsSqlTable<T>> List<T> awsmSelect(T obj, String where) {
    HashMap<String, String> params =
        new HashMap<String, String>() {
          {
            put("table", obj.locator());
            if (where != null) {
              put("where", String.format("where\n\t\t%s", where));
            } else {
              put("where", "");
            }
          }
        };
    String queryText = IsaCommonMethods.resolvePattern(STR_SELECT_QUERY_PATTERN, params);
    return super.fetchQueriedEntities(queryText, obj);
  }

  @Step("DB:: do select")
  public <T extends BsSqlTable> List<T> awsmSelectNew(T obj, String where) {
    HashMap<String, String> params =
        new HashMap<String, String>() {
          {
            Object collect =
                obj.fields().stream()
                    .map(
                        o -> {
                          Object o1 = o;
                          String to =
                              CaseFormat.LOWER_CAMEL.to(
                                  CaseFormat.UPPER_UNDERSCORE, String.valueOf(o1));
                          return to;
                        })
                    .collect(Collectors.joining(", "));
            put("fields", String.valueOf(collect));
            put("table", obj.locator());
            if (where != null) {
              put("where", String.format("where\n\t\t%s", where));
            } else {
              put("where", "");
            }
          }
        };
    String queryText = IsaCommonMethods.resolvePattern(STR_SELECT_QUERY_PATTERN_NEW, params);
    return super.fetchQueriedEntities(queryText, obj);
  }

  @Step("DB:: do update")
  public <T extends BsSnEntity<T>> List<T> awsmUpdate(T obj) {
    final Integer id = obj.getRow();
    obj.withRow(null);
    Map<String, String> queryParamsMap =
        gson.fromJson(gson.toJson(obj), new TypeToken<Map<String, String>>() {}.getType());
    return super.fetchQueriedEntities(
        IsaCommonMethods.resolvePattern(
            STR_UPDATE_QUERY_PATTERN,
            new HashMap<String, String>() {
              {
                put("schema", "public");
                put("table", obj.tableName());
                put(
                    "set",
                    queryParamsMap.entrySet().stream()
                        .map(o -> String.format("%s = '%s'", o.getKey(), o.getValue()))
                        .collect(Collectors.joining("\n, ")));
                put("where", String.format("unit_of_work_id = %s", Objects.requireNonNull(id)));
              }
            }),
        obj);
  }
}
