package io.delphi.qa.auto.awsmfrw.models.db.sql.dsl;

import org.apache.commons.lang3.ArrayUtils;

import java.util.Arrays;
import java.util.stream.Collectors;

public class DslSqlSelect extends AbstractDslSqlQuery implements InterfaceDslSqlQuery {

  public DslSqlSelect() {
    this.withQueryArray(ArrayUtils.addAll(this.getQueryArray(), "select"));
  }

  public DslSqlSelect(String... sqlColumnItems) {
    this();
    String format =
        sqlColumnItems.length == 0
            ? InterfaceDslSqlQuery.ALL
            : sqlColumnItems.length > 1
                ? Arrays.stream(sqlColumnItems)
                    .map(
                        item ->
                            String.format(
                                "(%s) as %s_%s\n", item, item, InterfaceDslSqlQuery.RESULT))
                    .collect(Collectors.joining(", "))
                : InterfaceDslSqlQuery.ALL.equals(sqlColumnItems[0])
                    ? InterfaceDslSqlQuery.ALL
                    : String.format("%s as %s", sqlColumnItems[0], InterfaceDslSqlQuery.RESULT);
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), format));
  }

  public DslSqlSelect(InterfaceDslSqlQuery... sqlQuery) {
    this();
    if (sqlQuery.length > 1)
      Arrays.stream(sqlQuery)
          .forEach(
              o ->
                  this.withQueryArray(
                      ArrayUtils.addAll(
                          getQueryArray(),
                          String.format(
                              "(%s) as %s", o.queryText(), InterfaceDslSqlQuery.RESULT))));
    else {
      this.withQueryArray(ArrayUtils.addAll(getQueryArray(), sqlQuery[0].getQueryArray()));
    }
  }

  public DslSqlSelect and(String xCondition) {
    this.withQueryArray(
        ArrayUtils.addAll(getQueryArray(), String.format("\n\t and (%s)", xCondition)));
    return this;
  }

  public DslSqlSelect distinct(String xColumnName) {
    this.withQueryArray(
        ArrayUtils.addAll(getQueryArray(), String.format(" distinct (%s)", xColumnName)));
    return this;
  }

  @Deprecated
  public DslSqlSelect columns(String... xColumnItems) {
    String format =
        xColumnItems.length == 0
            ? InterfaceDslSqlQuery.ALL
            : xColumnItems.length > 1
                ? Arrays.stream(xColumnItems)
                    .map(
                        item ->
                            String.format(
                                "(%s) as %s_%s\n", item, item, InterfaceDslSqlQuery.RESULT))
                    .collect(Collectors.joining(", "))
                : InterfaceDslSqlQuery.ALL.equals(xColumnItems[0])
                    ? InterfaceDslSqlQuery.ALL
                    : String.format("%s as %s", xColumnItems[0], InterfaceDslSqlQuery.RESULT);
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), format));
    return this;
  }

  @Deprecated
  public DslSqlSelect columns(InterfaceDslSqlQuery xSqlFuncResult) {
    this.withQueryArray(
        ArrayUtils.addAll(
            getQueryArray(),
            String.format("%s) as %s", xSqlFuncResult.queryText(), InterfaceDslSqlQuery.RESULT)));
    return this;
  }

  public DslSqlSelect from(String... xInnerQuery) {
    String format = String.format("\n\t from (%s", String.join(" ", xInnerQuery));
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), format));
    return this;
  }

  public DslSqlSelect innerJoin(String... xInnerQuery) {
    String format = String.format("\n\t inner join %s", String.join(" ", xInnerQuery));
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), format));
    return this;
  }

  public DslSqlSelect fromNoBraskets(String... xInnerQuery) {
    String format = String.format("\n\t from %s", String.join(" ", xInnerQuery));
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), format));
    return this;
  }

  @Override
  public String[] getQueryArray() {
    return this.queryArray;
  }

  @Override
  public DslSqlSelect withQueryArray(String[] xQueryArray) {
    this.queryArray = xQueryArray;
    return this;
  }

  @Override
  public DslSqlSelect open() {
    this.withQueryArray(ArrayUtils.addAll(getQueryArray(), " ("));
    return this;
  }

  public DslSqlSelect unionAll(String xSqlQueries) {
    this.withQueryArray(
        ArrayUtils.addAll(getQueryArray(), String.format(")\n\t union all (%s", xSqlQueries)));
    return this;
  }

  public DslSqlSelect limit(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format(") limit %s", xCondition)));
    return this;
  }

  public DslSqlSelect limitNoBracket(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format("limit %s", xCondition)));
    return this;
  }

  public DslSqlSelect where(String xCondition) {
    this.withQueryArray(
        ArrayUtils.addAll(getQueryArray(), String.format(")\n\t where (%s", xCondition)));
    return this;
  }

  public DslSqlSelect whereNoBracket(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format("\n\t where (%s", xCondition)));
    return this;
  }

  public DslSqlSelect orderByDesc(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format(") order by %s desc", xCondition)));
    return this;
  }

  public DslSqlSelect orderByDescNoBraskets(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format(" order by %s desc", xCondition)));
    return this;
  }

  public DslSqlSelect groupBy(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format(" group by %s ", xCondition)));
    return this;
  }

  public DslSqlSelect equalTo(String xCondition) {
    this.withQueryArray(
            ArrayUtils.addAll(getQueryArray(), String.format(" = %s", xCondition)));
    return this;
  }

  @Override
  public String toString() {
    return this.queryPgText();
  }
}
