package io.aiven.klaw.repository;

import io.aiven.klaw.dao.TopicRequest;
import io.aiven.klaw.dao.TopicRequestID;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.QueryByExampleExecutor;

public interface TopicRequestsRepo
    extends CrudRepository<TopicRequest, TopicRequestID>, QueryByExampleExecutor<TopicRequest> {
  Optional<TopicRequest> findById(TopicRequestID topicRequestId);

  List<TopicRequest> findAllByTenantId(int tenantId);

  boolean existsByTenantIdAndEnvironmentAndRequestStatusAndTopicname(
      int tenantId, String environment, String requestStatus, String topicname);

  boolean existsByTenantIdAndEnvironmentAndRequestStatusAndRequestOperationTypeAndTopicname(
      int tenantId,
      String environment,
      String requestStatus,
      String requestOperationType,
      String topicname);

  boolean existsByTenantIdAndRequestStatusAndRequestOperationTypeAndTopicname(
      int tenantId, String requestStatus, String requestOperationType, String topicname);

  boolean existsByTenantIdAndRequestStatusAndTopicname(
      int tenantId, String requestStatus, String topicname);

  boolean existsByTenantIdAndEnvironmentAndRequestStatus(
      int tenantId, String environment, String requestStatus);

  List<TopicRequest> findAllByRequestStatusAndTopicnameAndEnvironmentAndTenantId(
      String topicStatus, String topicName, String envId, int tenantId);

  boolean existsByRequestStatusAndTopicnameAndEnvironmentAndTenantId(
      String topicStatus, String topicName, String envId, int tenantId);

  boolean existsByEnvironmentAndTenantId(
      @Param("envId") String envId, @Param("tenantId") Integer tenantId);

  boolean existsByTeamIdAndTenantIdAndRequestStatus(
      Integer teamId, Integer tenantId, String requestStatus);

  boolean existsByRequestorAndTenantIdAndRequestStatus(
      String requestor, Integer tenantId, String requestStatus);

  @Query(
      value = "select max(topicid) from kwtopicrequests where tenantid = :tenantId",
      nativeQuery = true)
  Integer getNextTopicRequestId(@Param("tenantId") Integer tenantId);

  @Query(
      value =
          "select topictype, count(*) from kwtopicrequests where tenantid = :tenantId"
              + " and teamid = :teamId group by topictype",
      nativeQuery = true)
  List<Object[]> findAllTopicRequestsGroupByOperationType(
      @Param("teamId") Integer teamId, @Param("tenantId") Integer tenantId);

  default Map<String, Long> getCountPerTopicType(Integer teamId, Integer tenantId) {
    return deriveCountsFromRequests(findAllTopicRequestsGroupByOperationType(teamId, tenantId));
  }

  @Query(
      value =
          "select topicstatus, count(*) from kwtopicrequests where tenantid = :tenantId"
              + " and teamid = :teamId group by topicstatus",
      nativeQuery = true)
  List<Object[]> findCountPerTopicStatus(
      @Param("teamId") Integer teamId, @Param("tenantId") Integer tenantId);

  default Map<String, Long> getCountPerTopicStatus(Integer teamId, Integer tenantId) {
    return deriveCountsFromRequests(findCountPerTopicStatus(teamId, tenantId));
  }

  @Query(
      value =
          "select count(*) from kwtopicrequests where tenantid = :tenantId"
              + " and approvingteamId = :approvingteamId and topictype = :topictype",
      nativeQuery = true)
  long countAllTopicRequestsByApprovingTeamAndTopictype(
      @Param("tenantId") Integer tenantId,
      @Param("approvingteamId") String approvingteamId,
      @Param("topictype") String requestOperationType);

  @Query(
      value =
          "select count(*) from kwtopicrequests where tenantid = :tenantId"
              + " and ((teamid = :teamId and topictype != 'Claim')"
              + " or (approvingteamid = :approvingTeamId and topictype = 'Claim'))"
              + " and requestor != :requestor and topicstatus = :topicStatus group by topicstatus",
      nativeQuery = true)
  Long countRequestorsTopicRequestsGroupByStatusType(
      @Param("teamId") Integer teamId,
      @Param("approvingTeamId") String approvingTeamId,
      @Param("tenantId") Integer tenantId,
      @Param("requestor") String requestor,
      @Param("topicStatus") String topicStatus);

  void deleteByTenantId(int tenantId);

  private Map<String, Long> deriveCountsFromRequests(List<Object[]> list) {
    var result = new HashMap<String, Long>(list.size());
    for (var elem : list) {
      result.put((String) elem[0], (Long) elem[1]);
    }
    return result;
  }
}
