/*
 * (c) 2021 Pluto Inc.
 */
package tv.pluto;

import static com.mongodb.client.model.Projections.include;
import static tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.RatingDescriptor;

import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.TmsLink;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.rating_descriptors.RatingDescriptorsClient;
import tv.pluto.mongo.dto.ContentFeedQuery;
import tv.pluto.mongo.entities.ratingdescriptors.RatingDescriptors;
import tv.pluto.mongo.utils.RatingDescriptorsUtils;

public class RatingDescriptorsTestSuite extends BaseTest {
  private RatingDescriptorsClient ratingDescriptorsClient;
  private RatingDescriptorsUtils ratingDescriptorsUtils;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    ratingDescriptorsClient = new RatingDescriptorsClient(grpcChannelManager.getChannel());
    ratingDescriptorsUtils = new RatingDescriptorsUtils();
  }

  @Test
  @Description(
      "GetDocumentsUpdatedBetweenDates - Time period for which there is a rating descriptor")
  @TmsLink("28501230")
  public void C28501230_TEST() {

    ContentFeedQuery contentFeedQuery =
        ContentFeedQuery.builder()
            .updatedAtMin(ratingDescriptorsUtils.updatedAtMin)
            .updatedAtMax(ratingDescriptorsUtils.updatedAtMax)
            .limit(0)
            .projections(include("id"))
            .build();

    List<RatingDescriptors> mongoRatingDescriptors =
        ratingDescriptorsUtils.getDocumentsForContentFeeds(contentFeedQuery);

    List<RatingDescriptors> grpcRatingDescriptors = new ArrayList<>();

    Iterator<RatingDescriptor> ratingDescriptors =
        ratingDescriptorsClient.getDocumentsUpdatedBetweenDates(
            ratingDescriptorsUtils.updatedAtMinString, ratingDescriptorsUtils.updatedAtMaxString);

    while (ratingDescriptors.hasNext()) {
      grpcRatingDescriptors.add(
          ratingDescriptorsUtils.mapGrpcObjectToPojo(
              ratingDescriptors.next(), RatingDescriptors.class));
    }

    mongoRatingDescriptors.sort(Comparator.comparing(RatingDescriptors::getId));
    grpcRatingDescriptors.sort(Comparator.comparing(RatingDescriptors::getId));

    List<String> mongoIds = mongoRatingDescriptors.stream().map(RatingDescriptors::getId).toList();
    List<String> grpcIds = grpcRatingDescriptors.stream().map(RatingDescriptors::getId).toList();

    Assert.assertEquals(
        mongoIds, grpcIds, "The IDs do not match between Mongo and gRPC rating descriptors.");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("GetDocumentsUpdatedBetweenDates - Time period without rating descriptor")
  @TmsLink("28501231")
  public void C28501231_TEST() {
    ratingDescriptorsClient
        .getDocumentsUpdatedBetweenDates(failStartDateTime, failEndDateTime)
        .next();
  }

  @Test(
      dataProvider = "fail-content-feeds-test-data",
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = INVALID_ARGUMENT_MESSAGE)
  @Description(
      "GetDocumentsUpdatedBetweenDates - Invalid values for start_date_time and end_date_time")
  @TmsLink("28501232")
  public void C28501232_TEST(String startDateTime, String endDateTime) {
    ratingDescriptorsClient.getDocumentsUpdatedBetweenDates(startDateTime, endDateTime).next();
  }

  @Test(
      dataProvider = "less-or-equal-fail-content-feeds-test-data",
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = INTERNAL_ERROR_MESSAGE)
  @Description(
      "GetDocumentsUpdatedBetweenDates - end_date_time is less than or equal to start_date_time")
  @TmsLink("28501233")
  public void C28501233_TEST(String startDateTime, String endDateTime) {
    ratingDescriptorsClient.getDocumentsUpdatedBetweenDates(startDateTime, endDateTime).next();
  }

  @Test
  @Description("GetAllPaged - one ratingDescriptor")
  @TmsLink("28501242")
  public void C28501242_TEST() {
    int limit = 1;
    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort> grpcSort =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort.newBuilder()
                .setField("_id")
                .setValue(1)
                .build());

    tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedResponse response =
        new RatingDescriptorsClient(grpcChannelManager.getChannel())
            .getAllPaged(limit, 0, grpcSort, null, null);

    Assert.assertEquals(limit, response.getDocumentsList().size());
    RatingDescriptor ratingDescriptor = response.getDocumentsList().get(0);
    RatingDescriptors grpcRatingDescriptors =
        ratingDescriptorsUtils.mapGrpcObjectToPojo(ratingDescriptor, RatingDescriptors.class);

    RatingDescriptors mongoRatingDescriptors =
        ratingDescriptorsUtils.getDocumentById(grpcRatingDescriptors.getId());
    Assert.assertEquals(mongoRatingDescriptors, grpcRatingDescriptors);
  }

  @Test
  @Description("GetAllPaged - verify all ratingDescriptors")
  @TmsLink("28501243")
  public void C28501243_TEST() {
    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort> grpcSort =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort.newBuilder()
                .setField("_id")
                .setValue(1)
                .build());

    tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedResponse response =
        new RatingDescriptorsClient(grpcChannelManager.getChannel())
            .getAllPaged(null, 0, grpcSort, null, null);

    List<RatingDescriptors> grpcRatingDescriptors =
        ratingDescriptorsUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), RatingDescriptors.class);

    List<RatingDescriptors> mongoRatingDescriptors = ratingDescriptorsUtils.getDocuments(999999);
    Collections.sort(grpcRatingDescriptors, Comparator.comparing(RatingDescriptors::getId));
    Collections.sort(mongoRatingDescriptors, Comparator.comparing(RatingDescriptors::getId));
    Assert.assertEquals(mongoRatingDescriptors, grpcRatingDescriptors);
  }

  @Test
  @Description("GetAllPaged - ratingDescriptor filter by id")
  @TmsLink("28501244")
  public void C28501244_TEST() {
    RatingDescriptors ratingDoc = ratingDescriptorsUtils.getRandomDocument();

    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort> grpcSort =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort.newBuilder()
                .setField("_id")
                .setValue(1)
                .build());

    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.Filter> filter =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.Filter.newBuilder()
                .setField("_id")
                .setValue(ratingDoc.getId())
                .setType("string")
                .build());

    tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedResponse response =
        new RatingDescriptorsClient(grpcChannelManager.getChannel())
            .getAllPaged(null, 0, grpcSort, filter, true);

    Assert.assertEquals(1, response.getDocumentsList().size());
    RatingDescriptors grpcRatingDescriptors =
        ratingDescriptorsUtils.mapGrpcObjectToPojo(
            response.getDocumentsList().get(0), RatingDescriptors.class);

    Assert.assertEquals(ratingDoc, grpcRatingDescriptors);
  }

  @Test
  @Description("GetAllPaged - ratingDescriptor filter by region")
  @TmsLink("28501245")
  public void C28501245_TEST() {
    String region = ((RatingDescriptors) ratingDescriptorsUtils.getRandomDocument()).getRegion();
    List<RatingDescriptors> ratingDoc =
        ratingDescriptorsUtils.getDocumentsByKeyValue("region", region);
    Assert.assertFalse(ratingDoc.isEmpty());

    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort> grpcSort =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedSort.newBuilder()
                .setField("_id")
                .setValue(1)
                .build());

    List<tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.Filter> filter =
        Collections.singletonList(
            tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.Filter.newBuilder()
                .setField("region")
                .setValue(region)
                .setType("string")
                .build());

    tv.pluto.ip.dal.ratingdescriptor.RatingDescriptors.GetAllPagedResponse response =
        new RatingDescriptorsClient(grpcChannelManager.getChannel())
            .getAllPaged(null, 0, grpcSort, filter, true);

    List<RatingDescriptors> grpcRatingDescriptors =
        ratingDescriptorsUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), RatingDescriptors.class);
    Collections.sort(ratingDoc, Comparator.comparing(RatingDescriptors::getId));

    Assert.assertEquals(ratingDoc, grpcRatingDescriptors);
  }
}
