package build.bazel.dashboard.github.issuelist;

import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Objects.requireNonNull;

import build.bazel.dashboard.github.issuelist.GithubIssueListService.ListParams;
import build.bazel.dashboard.github.issuestatus.GithubIssueStatus;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableList;
import io.r2dbc.postgresql.codec.Json;
import io.r2dbc.postgresql.codec.PostgresqlObjectId;
import io.r2dbc.spi.Parameters;
import io.r2dbc.spi.Readable;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Single;
import java.io.IOException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import org.springframework.r2dbc.core.DatabaseClient;
import org.springframework.r2dbc.core.DatabaseClient.GenericExecuteSpec;
import org.springframework.stereotype.Repository;
import reactor.adapter.rxjava.RxJava3Adapter;

@Repository
@RequiredArgsConstructor
public class GithubIssueListRepoPg implements GithubIssueListRepo {

  private final ObjectMapper objectMapper;
  private final DatabaseClient databaseClient;

  @Builder
  static class QuerySpec {
    String from;
    String where;
    String order;
    String limit;
    Map<String, Object> bindings;
  }

  private static QuerySpec buildQuerySpec(ListParams params) {
    String from =
        " FROM github_issue_status gis INNER JOIN github_issue gi ON (gi.owner, gi.repo,"
            + " gi.issue_number) = (gis.owner, gis.repo, gis.issue_number) INNER JOIN"
            + " github_issue_data gid ON (gid.owner, gid.repo, gid.issue_number) = (gi.owner,"
            + " gi.repo, gi.issue_number)";

    Map<String, Object> bindings = new HashMap<>();
    StringBuilder where = new StringBuilder();

    if (params.getOwner() != null) {
      where.append(" AND gis.owner = :owner");
      bindings.put("owner", params.getOwner());
    }

    if (params.getRepo() != null) {
      where.append(" AND gis.repo = :repo");
      bindings.put("repo", params.getRepo());
    }

    if (params.getIsPullRequest() != null) {
      where.append(" AND gi.is_pull_request = :is_pull_request");
      bindings.put("is_pull_request", params.getIsPullRequest());
    }

    if (params.getStatus() != null) {
      where.append(" AND gis.status = :status");
      bindings.put("status", params.getStatus().toString());
    }

    if (params.getActionOwner() != null) {
      where.append(
          " AND (gis.action_owner = :action_owner OR :action_owner = ANY(gis.more_action_owners))");
      bindings.put("action_owner", params.getActionOwner());
    }

    if (params.getLabels() != null && !params.getLabels().isEmpty()) {
      where.append(" AND gi.labels @> :labels");
      bindings.put(
          "labels",
          Parameters.in(PostgresqlObjectId.UNSPECIFIED, params.getLabels().toArray(new String[0])));
    }

    if (where.length() > 0) {
      // Remove heading AND
      where.delete(0, 4);
      where.insert(0, " WHERE");
    }

    String order = " ORDER BY gi.issue_number DESC";

    if (params.getSort() != null) {
      switch (params.getSort()) {
        case EXPECTED_RESPOND_AT_ASC:
          order = " ORDER BY gis.expected_respond_at ASC";
          break;
        case EXPECTED_RESPOND_AT_DESC:
          order = " ORDER BY gis.expected_respond_at DESC";
          break;
      }
    }

    int page = requireNonNull(params.getPage());
    int pageSize = requireNonNull(params.getPageSize());
    int offset = (page - 1) * pageSize;
    String limit = " LIMIT " + pageSize + " OFFSET " + offset;

    return QuerySpec.builder()
        .from(from)
        .where(where.toString())
        .order(order)
        .limit(limit)
        .bindings(bindings)
        .build();
  }

  @Override
  public Flowable<GithubIssueList.Item> find(ListParams params) {
    QuerySpec query = buildQuerySpec(params);

    String fields =
        "gid.owner, gid.repo, gid.issue_number, gis.status, gis.action_owner,"
            + " gis.more_action_owners, gis.expected_respond_at, gid.data";
    String sql = "SELECT " + fields + query.from + query.where + query.order + query.limit;

    GenericExecuteSpec spec = databaseClient.sql(sql);
    for (Map.Entry<String, Object> binding : query.bindings.entrySet()) {
      spec = spec.bind(binding.getKey(), binding.getValue());
    }

    return RxJava3Adapter.fluxToFlowable(spec.map(this::toGithubIssueListItem).all());
  }

  @Override
  public Single<Integer> count(ListParams params) {
    QuerySpec query = buildQuerySpec(params);

    String sql = "SELECT COUNT(*) as total" + query.from + query.where;
    GenericExecuteSpec spec = databaseClient.sql(sql);
    for (Map.Entry<String, Object> binding : query.bindings.entrySet()) {
      spec = spec.bind(binding.getKey(), binding.getValue());
    }

    return RxJava3Adapter.monoToSingle(spec.map(row -> row.get("total", Integer.class)).one());
  }

  private GithubIssueList.Item toGithubIssueListItem(Readable row) {
    String actionOwner = row.get("action_owner", String.class);
    if (actionOwner == null) {
      String[] moreActionOwners = requireNonNull(row.get("more_action_owners", String[].class));
      if (moreActionOwners.length > 0) {
        actionOwner = moreActionOwners[0];
      }
    }

    try {
      return GithubIssueList.Item.builder()
          .owner(requireNonNull(row.get("owner", String.class)))
          .repo(requireNonNull(row.get("repo", String.class)))
          .issueNumber(requireNonNull(row.get("issue_number", Integer.class)))
          .status(GithubIssueStatus.Status.valueOf(row.get("status", String.class)))
          .actionOwner(actionOwner)
          .expectedRespondAt(row.get("expected_respond_at", Instant.class))
          .data(objectMapper.readTree((requireNonNull(row.get("data", Json.class))).asArray()))
          .build();
    } catch (IOException e) {
      throw new IllegalStateException(e);
    }
  }

  @Override
  public ImmutableList<String> findAllActionOwner(ListParams params) {
    if (params.getActionOwner() != null) {
      return ImmutableList.of(params.getActionOwner());
    }

    QuerySpec query = buildQuerySpec(params);

    StringBuilder sql =
        new StringBuilder(
            "SELECT DISTINCT unnest(array_append(gis.more_action_owners, gis.action_owner)) as"
                + " action_owner");
    sql.append(query.from);
    sql.append(query.where);

    GenericExecuteSpec spec = databaseClient.sql(sql.toString());
    for (Map.Entry<String, Object> binding : query.bindings.entrySet()) {
      spec = spec.bind(binding.getKey(), binding.getValue());
    }

    return spec.map(
            row -> {
              String actionOwner = row.get("action_owner", String.class);
              if (actionOwner == null) {
                actionOwner = "";
              }
              return actionOwner;
            })
        .all()
        .collect(toImmutableList())
        .block();
  }

  @Override
  public ImmutableList<String> findAllLabels(ListParams params) {
    QuerySpec query = buildQuerySpec(params);
    StringBuilder sql = new StringBuilder("SELECT DISTINCT unnest(gi.labels) AS label");
    sql.append(query.from);
    sql.append(query.where);

    GenericExecuteSpec spec = databaseClient.sql(sql.toString());
    for (Map.Entry<String, Object> binding : query.bindings.entrySet()) {
      spec = spec.bind(binding.getKey(), binding.getValue());
    }

    return spec.map(row -> requireNonNull(row.get("label", String.class)))
        .all()
        .collect(toImmutableList())
        .block();
  }
}
