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

import static com.mongodb.client.model.Projections.include;
import static com.mongodb.client.model.Sorts.ascending;
import static com.mongodb.client.model.Sorts.descending;
import static com.mongodb.client.model.Sorts.orderBy;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.Filter;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetAllPagedResponse;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetAllPagedSort;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetByIdResponse;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetPopulatedEntriesByVodCategoryIdResponse;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetVodCategoryEntriesByVodCategoryIdResponse;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.PopulatedVodCategoryEntry;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.SortOptions;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.UpdateFieldsResponse;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.UpdateOrderElement;
import static tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.VodCategoryEntry;
import static tv.pluto.mongo.utils.MongoUtils.INVALID_ID_VALUE;

import com.plutotv.test.lib.LogUtils;
import io.grpc.Status;
import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.TmsLink;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.vod_category_entries.VodCategoryEntriesClient;
import tv.pluto.mongo.dto.ContentFeedQuery;
import tv.pluto.mongo.entities.clips.Clips;
import tv.pluto.mongo.entities.common.Window;
import tv.pluto.mongo.entities.episodes.Episodes;
import tv.pluto.mongo.entities.episodes.Source;
import tv.pluto.mongo.entities.series.Series;
import tv.pluto.mongo.entities.vodcategoryentries.VodCategoryEntries;
import tv.pluto.mongo.utils.ClipsUtils;
import tv.pluto.mongo.utils.SeriesUtils;
import tv.pluto.mongo.utils.VodCategoryEntriesUtils;
import tv.pluto.mongo.utils.VodCategoryUtils;
import tv.pluto.mongo.utils.episodes.EpisodeUtils;
import tv.pluto.utils.CommonUtils;

public class VodCategoryEntriesTestSuite extends BaseTest {
  private VodCategoryEntriesClient vodCategoryEntriesClient;
  private VodCategoryEntriesClient vodCategoryEntriesClientAuth;
  private VodCategoryEntriesUtils vodCategoryEntriesUtils;
  private VodCategoryUtils vodCategoryUtils;
  private SeriesUtils seriesUtils;
  private EpisodeUtils episodeUtils;
  private ClipsUtils clipsUtils;
  private boolean isBulkDeleteWorked = false;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    vodCategoryEntriesClient = new VodCategoryEntriesClient(grpcChannelManager.getChannel(), false);
    vodCategoryEntriesClientAuth =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true);
    vodCategoryEntriesUtils = new VodCategoryEntriesUtils();
    vodCategoryUtils = new VodCategoryUtils();
    seriesUtils = new SeriesUtils();
    episodeUtils = new EpisodeUtils();
    clipsUtils = new ClipsUtils();
  }

  @Test
  @Description(
      "GetDocumentsUpdatedBetweenDates - Time period for which there is a vod category entries")
  @TmsLink("28501692")
  public void C28501692_TEST() {

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

    List<VodCategoryEntries> mongoVodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentsForContentFeeds(contentFeedQuery);
    List<VodCategoryEntries> grpcVodCategoryEntries = new ArrayList<>();

    Iterator<VodCategoryEntry> vodCategoryEntries =
        vodCategoryEntriesClient.getDocumentsUpdatedBetweenDates(
            vodCategoryEntriesUtils.updatedAtMinString, vodCategoryEntriesUtils.updatedAtMaxString);

    while (vodCategoryEntries.hasNext()) {
      grpcVodCategoryEntries.add(
          vodCategoryEntriesUtils.mapGrpcObjectToPojo(
              vodCategoryEntries.next(), VodCategoryEntries.class));
    }

    mongoVodCategoryEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcVodCategoryEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    List<String> mongoIds =
        mongoVodCategoryEntries.stream().map(VodCategoryEntries::getId).toList();
    List<String> grpcIds = grpcVodCategoryEntries.stream().map(VodCategoryEntries::getId).toList();

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

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("GetDocumentsUpdatedBetweenDates - Time period without vod category entries")
  @TmsLink("28501693")
  public void C28501693_TEST() {
    vodCategoryEntriesClient
        .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("28501694")
  public void C28501694_TEST(String startDateTime, String endDateTime) {
    vodCategoryEntriesClient.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("28501695")
  public void C28501695_TEST(String startDateTime, String endDateTime) {
    vodCategoryEntriesClient.getDocumentsUpdatedBetweenDates(startDateTime, endDateTime).next();
  }

  @Test
  @Description("CFeedsSyncAllIds - get CFEEDs ids")
  @TmsLink("28501713")
  public void C28501713_TEST() {
    Iterator<tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.Id> idIterator =
        vodCategoryEntriesClient.cFeedsSyncAllIdsIterator();
    List<String> listGrpcIds = new ArrayList<>();
    int total = 0;
    while (idIterator.hasNext() && total < 50) {
      listGrpcIds.add(idIterator.next().getId());
      total++;
    }

    int mongoVodCategoryEntriesSize = vodCategoryEntriesUtils.getDocumentsByIds(listGrpcIds).size();
    Assert.assertTrue(mongoVodCategoryEntriesSize > 0);
    Assert.assertEquals(mongoVodCategoryEntriesSize, listGrpcIds.size());
  }

  @Test
  @Description("cFeedsSyncDocuments - last_run_at")
  @TmsLink("28501712")
  public void C28501712_TEST() {
    VodCategoryEntries randomVodCategoryEntries =
        vodCategoryEntriesUtils.getVodCategoryEntries(1).get(0);
    List<VodCategoryEntries> mongoVodCategoryEntries =
        vodCategoryEntriesUtils.getAllVodCategoryEntriesWithinUpdatedDate(
            randomVodCategoryEntries.getUpdatedAt());
    List<VodCategoryEntries> grpcListVodCategoryEntries = new ArrayList<>();
    vodCategoryEntriesClient
        .cFeedsSyncSyncDocumentsList(randomVodCategoryEntries.getUpdatedAtString())
        .forEach(
            VodCategoryEntries ->
                grpcListVodCategoryEntries.add(
                    vodCategoryEntriesUtils.mapGrpcObjectToPojo(
                        VodCategoryEntries, VodCategoryEntries.class)));

    mongoVodCategoryEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcListVodCategoryEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertFalse(grpcListVodCategoryEntries.isEmpty());
    Assert.assertEquals(mongoVodCategoryEntries, grpcListVodCategoryEntries);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("cFeedsSyncDocuments - last_run_at now time. Negative scenario")
  @TmsLink("28501714")
  public void C28501714_TEST() {
    LocalDateTime nowTime = LocalDateTime.now(ZoneOffset.UTC).plusYears(10);
    int mongoVodCategoryEntries =
        vodCategoryEntriesUtils.getAllVodCategoryEntriesWithinUpdatedDate(nowTime).size();
    Assert.assertEquals(mongoVodCategoryEntries, 0);

    vodCategoryEntriesClient.cFeedsSyncSyncDocumentsList(nowTime.toString()).get(0);
  }

  @Test
  @Description("GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing series IDs and episodes IDs")
  @TmsLink("28501704")
  public void C28501704_TEST() {
    List<String> seriesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithSeries();
    List<String> episodesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithEpisodes();

    LogUtils.logInfoMessage("Series ids for C9019641_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019641_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, null)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing series IDs and episodes IDs projections")
  @TmsLink("28501711")
  public void C28501711_TEST() {
    String[] projection = {"_id", "vodCategory"};
    List<String> seriesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithSeries();
    List<String> episodesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithEpisodes();

    LogUtils.logInfoMessage("Series ids for C9019641_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019641_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, projection);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, projection)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing episodes IDs, series IDs empty")
  @TmsLink("28501705")
  public void C28501705_TEST() {
    List<String> seriesIds = Collections.emptyList();
    List<String> episodesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithEpisodes();

    LogUtils.logInfoMessage("Series ids for C9019644_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019644_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, null)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing series IDs, episodes IDs empty")
  @TmsLink("28501706")
  public void C28501706_TEST() {
    List<String> seriesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithSeries();
    List<String> episodesIds = Collections.emptyList();

    LogUtils.logInfoMessage("Series ids for C9019645_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019645_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, null)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing episodes IDs, series IDs list has one invalid value")
  @TmsLink("28501707")
  public void C28501707_TEST() {
    List<String> seriesIds = Collections.singletonList(INVALID_ID_VALUE);
    List<String> episodesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithEpisodes();

    LogUtils.logInfoMessage("Series ids for C9019646_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019646_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, null)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - Existing series IDs, episodes list has one invalid value")
  @TmsLink("28501708")
  public void C28501708_TEST() {
    List<String> seriesIds = vodCategoryEntriesUtils.getVodCategoryEntriesWithSeries();
    List<String> episodesIds = Collections.singletonList(INVALID_ID_VALUE);

    LogUtils.logInfoMessage("Series ids for C9019647_TEST " + seriesIds);
    LogUtils.logInfoMessage("Episodes ids for C9019647_TEST " + episodesIds);

    List<VodCategoryEntries> mongoEntries =
        vodCategoryEntriesUtils.getVodCategoryEntriesBySeriesOrEpisodeIds(
            seriesIds, episodesIds, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesClient
                .getVodCategoryEntriesBySeriesOrEpisodeIds(seriesIds, episodesIds, null)
                .getDocumentsList(),
            VodCategoryEntries.class);

    mongoEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    grpcEntries.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds - series IDs list and episodes IDs list are both empty")
  @TmsLink("28501709")
  public void C28501709_TEST() {
    try {
      vodCategoryEntriesClient.getVodCategoryEntriesBySeriesOrEpisodeIds(
          Collections.emptyList(), Collections.emptyList(), null);
    } catch (StatusRuntimeException e) {
      Assert.assertEquals(e.getStatus().getCode(), Status.FAILED_PRECONDITION.getCode());
      Assert.assertEquals(
          e.getMessage(),
          "FAILED_PRECONDITION: Request params must contain at least one series or episode IDs");
    }
  }

  @Test
  @Description(
      "GetVodCategoryEntriesBySeriesOrEpisodeIds -  series IDs list and episodes IDs list are both has non existing ID")
  @TmsLink("28501710")
  public void C28501710_TEST() {
    try {
      vodCategoryEntriesClient.getVodCategoryEntriesBySeriesOrEpisodeIds(
          Collections.singletonList(INVALID_ID_VALUE),
          Collections.singletonList(INVALID_ID_VALUE),
          null);
    } catch (StatusRuntimeException e) {
      Assert.assertEquals(e.getStatus().getCode(), Status.NOT_FOUND.getCode());
      Assert.assertEquals(
          e.getMessage(),
          "NOT_FOUND: VodCategoryEntry documents for requested series or episode IDs not found");
    }
  }

  @Test
  @Description("UpdateFields - update the fields")
  @TmsLink("28501715")
  public void C28501715_TEST() {
    VodCategoryEntries vodCategoryEntry = vodCategoryEntriesUtils.getVodCategoryEntry();
    String id = vodCategoryEntry.getId();
    int newOrder = vodCategoryEntry.getOrder() + 1;
    String testValue = "58e1ae5c17d972af2febfa81";

    VodCategoryEntry vodCategoryBuild =
        VodCategoryEntry.newBuilder()
            .setOrder(newOrder)
            .setVodCategory(testValue)
            .setEpisode(testValue)
            .build();

    List<String> listFields = List.of("order", "vodCategory", "episode");
    UpdateFieldsResponse vodCategoryEntriesResponse =
        vodCategoryEntriesClient.updateFields(id, vodCategoryBuild, listFields);

    VodCategoryEntries grpcVodCategoryEntries =
        vodCategoryEntriesUtils.mapGrpcObjectToPojo(
            vodCategoryEntriesResponse.getDocument(), VodCategoryEntries.class);

    VodCategoryEntries mongoVodCategoryEntries = vodCategoryEntriesUtils.getDocumentById(id);

    SoftAssert softAssert = new SoftAssert();
    softAssert.assertEquals(mongoVodCategoryEntries, grpcVodCategoryEntries);
    softAssert.assertEquals(newOrder, mongoVodCategoryEntries.getOrder().intValue());
    softAssert.assertEquals(testValue, mongoVodCategoryEntries.getEpisode());
    softAssert.assertEquals(testValue, mongoVodCategoryEntries.getVodCategory());

    LocalDateTime beforeTime = mongoVodCategoryEntries.getUpdatedAt().minusSeconds(10);
    CommonUtils.isDateBetweenDates(beforeTime, mongoVodCategoryEntries.getUpdatedAt());

    VodCategoryEntry originalVodCategoryBuild =
        VodCategoryEntry.newBuilder()
            .setOrder(vodCategoryEntry.getOrder())
            .setVodCategory(vodCategoryEntry.getVodCategory())
            .setEpisode(vodCategoryEntry.getEpisode())
            .build();

    UpdateFieldsResponse vodCategoryEntriesRevertResponse =
        vodCategoryEntriesClient.updateFields(id, originalVodCategoryBuild, listFields);

    softAssert.assertEquals(
        vodCategoryEntry.getVodCategory(),
        vodCategoryEntriesRevertResponse.getDocument().getVodCategory());
    softAssert.assertAll();
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("UpdateFields - INTERNAL exception")
  @TmsLink("28501717")
  public void C28501717_TEST() {
    VodCategoryEntry vodCategoryBuild = VodCategoryEntry.newBuilder().setEpisode("test").build();
    vodCategoryEntriesClient.updateFields("test", vodCategoryBuild, List.of("episode"));
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategoryEntry for requested query not found to be updated")
  @Description("UpdateFields - invalid id")
  @TmsLink("28501716")
  public void C28501716_TEST() {
    VodCategoryEntries vodCategoryEntry = vodCategoryEntriesUtils.getVodCategoryEntry();
    int newOrder = vodCategoryEntry.getOrder() + 1;
    String testValue = "9999ae5c17d972af99999999";

    VodCategoryEntry vodCategoryBuild =
        VodCategoryEntry.newBuilder()
            .setOrder(newOrder)
            .setVodCategory(testValue)
            .setEpisode(testValue)
            .build();

    List<String> listFields = List.of("order", "vodCategory", "episode");
    vodCategoryEntriesClient.updateFields(testValue, vodCategoryBuild, listFields);
  }

  @Test
  @Description("CreateRequest - creates VodCategoryEntries")
  @TmsLink("28501718")
  public void C28501718_TEST() {
    String random = new ObjectId().toString();
    int order = 99;

    VodCategoryEntry vodCategoryEntry =
        VodCategoryEntry.newBuilder()
            .setSeries(random)
            .setEpisode(random)
            .setOrder(order)
            .setVodCategory(random)
            .build();

    LogUtils.logInfoMessage("Created VodCategoryEntry id: " + vodCategoryEntry.getId());

    VodCategoryEntry vodResponse =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true)
            .getCreateRequest(vodCategoryEntry)
            .getDocument();
    VodCategoryEntries grpcVodCategories =
        vodCategoryEntriesUtils.mapGrpcObjectToPojo(vodResponse, VodCategoryEntries.class);
    VodCategoryEntries vodMango = vodCategoryEntriesUtils.getDocumentById(vodResponse.getId());

    SoftAssert softAssert = new SoftAssert();
    softAssert.assertEquals(random, vodResponse.getSeries());
    softAssert.assertEquals(random, vodResponse.getEpisode());
    softAssert.assertEquals(order, vodResponse.getOrder());

    softAssert.assertEquals(grpcVodCategories, vodMango);
    softAssert.assertAll();
  }

  @Test(expectedExceptions = StatusRuntimeException.class)
  @Description("CreateRequest - validation failed")
  @TmsLink("28501719")
  public void C28501719_TEST() {
    VodCategoryEntry vodCategoryEntry =
        VodCategoryEntry.newBuilder()
            .setSeries(UUID.randomUUID().toString())
            .setEpisode(UUID.randomUUID().toString())
            .build();

    vodCategoryEntriesClientAuth.getCreateRequest(vodCategoryEntry);
  }

  @Test
  @Description("GetVodCategoryEntriesByVodCategoryId - vodcategories in vodcategoryentries")
  @TmsLink("28501720")
  public void C28501720_TEST() {
    VodCategoryEntries vodCategoryEntries = vodCategoryEntriesUtils.getRandomDocument();
    List<VodCategoryEntries> listVodCategories =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId(
            "vodCategory", vodCategoryEntries.getVodCategory());

    GetVodCategoryEntriesByVodCategoryIdResponse vodCategoryEntriesByVodCategoryId =
        vodCategoryEntriesClient.getVodCategoryEntriesByVodCategoryId(
            vodCategoryEntries.getVodCategory());

    List<VodCategoryEntries> grpcListVodCategoryEntries =
        vodCategoryUtils.mapGrpcObjectsToPojo(
            vodCategoryEntriesByVodCategoryId.getDocumentsList(), VodCategoryEntries.class);
    Assert.assertNotNull(grpcListVodCategoryEntries);

    grpcListVodCategoryEntries.sort(Comparator.comparing(VodCategoryEntries::getId));
    listVodCategories.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertEquals(grpcListVodCategoryEntries, listVodCategories);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategoryEntry documents for requested vodCategory id not found")
  @Description("GetVodCategoryEntriesByVodCategoryId - invalid vodcategories")
  @TmsLink("28501721")
  public void C28501721_TEST() {
    vodCategoryEntriesClient.getVodCategoryEntriesByVodCategoryId("5b7ffc8f32f76d45a36aaaaa");
  }

  @Test
  @Description("DeleteById with authentication")
  @TmsLink("28501722")
  public void C28501722_TEST() {
    VodCategoryEntries vodCategoryEntries = vodCategoryEntriesUtils.getRandomDocument();
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.DeleteByIdResponse deleteByIdResponse =
        vodCategoryEntriesClientAuth.deleteByIdResponse(vodCategoryEntries.getId());

    Assert.assertEquals(deleteByIdResponse.getDeletedCount(), 1);
    Assert.assertNull(vodCategoryEntriesUtils.getDocumentById(vodCategoryEntries.getId()));
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "UNAUTHENTICATED: DB deletes not allowed without authentication")
  @Description("DeleteById without authentication")
  @TmsLink("28501723")
  public void C28501723_TEST() {
    VodCategoryEntries vodCategoryEntries = vodCategoryEntriesUtils.getRandomDocument();
    vodCategoryEntriesClient.deleteByIdResponse(vodCategoryEntries.getId());
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategoryEntry documents for requested IDs not found")
  @Description("DeleteById with authentication with invalid id")
  @TmsLink("28501724")
  public void C28501724_TEST() {
    vodCategoryEntriesClientAuth.deleteByIdResponse("9999a38d148974c999999999");
  }

  @Test
  @Description("GetById - get the id")
  @TmsLink("28501725")
  public void C28501725_TEST() {
    VodCategoryEntries mongoVodCategory = vodCategoryEntriesUtils.getRandomDocument();
    LogUtils.logInfoMessage("VodCategoryEntries id: " + mongoVodCategory.getId());
    GetByIdResponse byId = vodCategoryEntriesClient.getById(mongoVodCategory.getId());
    VodCategoryEntries grpcId =
        vodCategoryEntriesUtils.mapGrpcObjectToPojo(byId.getDocument(), VodCategoryEntries.class);

    Assert.assertEquals(mongoVodCategory, grpcId);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategoryEntry document for requested ID not found")
  @Description("GetById - get the invalid id")
  @TmsLink("28501726")
  public void C28501726_TEST() {
    vodCategoryEntriesClient.getById("5899966e148974c9ae7f9999");
  }

  @Test
  @Description("GetAllPagedSort - filter by id")
  @TmsLink("28501727")
  public void C28501727_TEST() {
    VodCategoryEntries mongoVodCategory = vodCategoryEntriesUtils.getRandomDocument();
    GetAllPagedSort sort = GetAllPagedSort.newBuilder().setField("vodCategory").setValue(1).build();
    Filter filter =
        Filter.newBuilder()
            .setField("_id")
            .setValue(mongoVodCategory.getId())
            .setType("string")
            .build();

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(
            10, 0, Collections.singletonList(sort), Collections.singletonList(filter), true);

    boolean allDocsMatchIds =
        response.getDocumentsList().stream()
            .allMatch(e -> e.getId().equals(mongoVodCategory.getId()));
    Assert.assertTrue(allDocsMatchIds);
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting ascending by single field")
  @TmsLink("28501728")
  public void C28501728_TEST() {
    Bson sort = orderBy(ascending("_id"));
    List<VodCategoryEntries> mongoEntries = vodCategoryEntriesUtils.getDocuments(20, 10, sort);

    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(GetAllPagedSort.newBuilder().setField("_id").setValue(1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), VodCategoryEntries.class);

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting ascending by multiple fields")
  @TmsLink("28501729")
  public void C28501729_TEST() {
    Bson sort = orderBy(ascending("_id"), ascending("name"));
    List<VodCategoryEntries> mongoEntries = vodCategoryEntriesUtils.getDocuments(20, 10, sort);

    List<GetAllPagedSort> grpcSort =
        Arrays.asList(
            GetAllPagedSort.newBuilder().setField("_id").setValue(1).build(),
            GetAllPagedSort.newBuilder().setField("vodCategory").setValue(1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), VodCategoryEntries.class);

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting descending by single field")
  @TmsLink("28501730")
  public void C28501730_TEST() {
    Bson sort = orderBy(descending("_id"));
    List<VodCategoryEntries> mongoEntries = vodCategoryEntriesUtils.getDocuments(20, 10, sort);

    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("_id").setValue(-1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), VodCategoryEntries.class);

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description("GetAllPagedResponse - has a new object Metadata")
  @TmsLink("28501731")
  public void C28501731_TEST() {
    int offset = 9;
    int limit = 18;

    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("_id").setValue(-1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(limit, offset, grpcSort, null, true);

    Assert.assertEquals(response.getMetadata().getCurrentOffset(), offset);
    Assert.assertEquals(response.getMetadata().getTotalItems(), limit);
    Assert.assertEquals(response.getDocumentsList().size(), limit);
  }

  @Test
  @Description("GetAllPagedResponse - has a new object Metadata disable_total_count: false")
  @TmsLink("28501732")
  public void C28501732_TEST() {
    int offset = 9;
    int limit = 18;

    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("_id").setValue(-1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(limit, offset, grpcSort, null, false);
    long countTotalEpisodes = vodCategoryEntriesUtils.getDocumentsCountsInTheCollection();

    Assert.assertEquals(response.getMetadata().getCurrentOffset(), offset);
    Assert.assertEquals(response.getDocumentsList().size(), limit);
    Assert.assertTrue(countTotalEpisodes > 0);
    Assert.assertEquals(countTotalEpisodes, response.getMetadata().getTotalItems());
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting descending by multiple fields")
  @TmsLink("28501733")
  public void C28501733_TEST() {
    Bson sort = orderBy(descending("_id"), descending("name"));
    List<Episodes> mongoEntries = vodCategoryEntriesUtils.getDocuments(20, 10, sort);

    List<GetAllPagedSort> grpcSort =
        Arrays.asList(
            GetAllPagedSort.newBuilder().setField("_id").setValue(-1).build(),
            GetAllPagedSort.newBuilder().setField("vodCategory").setValue(-1).build());

    GetAllPagedResponse response =
        vodCategoryEntriesClient.getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategoryEntries> grpcEntries =
        vodCategoryEntriesUtils.mapGrpcObjectsToPojo(
            response.getDocumentsList(), VodCategoryEntries.class);

    Assert.assertEquals(mongoEntries, grpcEntries);
  }

  @Test
  @Description("GetAllPaged - get documents with default values")
  @TmsLink("28501734")
  public void C28501734_TEST() {
    VodCategoryEntriesClient newClient =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), false);
    GetAllPagedResponse response = newClient.getAllPaged(null, null, null, null, null);

    Assert.assertEquals(response.getDocumentsList().size(), DEFAULT_LIMIT); // Default value
  }

  @Test
  @Description("UpdateOrder - happy path for one document")
  @TmsLink("28501735")
  public void C28501735_TEST() {
    List<Integer> order = vodCategoryEntriesUtils.getDistinctListOfTheField("order", Integer.class);
    int newOrder = CommonUtils.listMissingIntegerFromListInOrder(order, 1).get(0);
    LogUtils.logInfoMessage("The new lowest order number: " + newOrder);

    VodCategoryEntries vodCategoriesEntries =
        vodCategoryEntriesUtils.getSortedDocumentByField("order", -1);
    String vodId = vodCategoriesEntries.getId();

    UpdateOrderElement docOrder =
        UpdateOrderElement.newBuilder().setId(vodId).setOrder(newOrder).build();

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.UpdateOrderResponse updateResponse =
        vodCategoryEntriesClient.updateOrder(
            vodCategoriesEntries.getVodCategory(), List.of(docOrder));
    Assert.assertEquals(vodId, updateResponse.getDocuments(0).getId());
    Assert.assertEquals(newOrder, updateResponse.getDocuments(0).getOrder());

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.VodCategoryEntry vodDocGrpc =
        vodCategoryEntriesClient.getById(vodId).getDocument();
    Assert.assertEquals(newOrder, vodDocGrpc.getOrder());
  }

  @Test
  @Description("UpdateOrder - happy path for multiple documents")
  @TmsLink("28501736")
  public void C28501736_TEST() {
    List<Integer> order = vodCategoryEntriesUtils.getDistinctListOfTheField("order", Integer.class);
    List<Integer> listMissingValues = CommonUtils.listMissingIntegerFromListInOrder(order, 2);

    int newOrder1 = listMissingValues.get(0);
    int newOrder2 = listMissingValues.get(1);
    LogUtils.logInfoMessage("The new lowest order number: " + newOrder1 + ", and : " + newOrder2);

    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getRandomDocument();
    String vodCategory = vodCategories.getVodCategory();

    List<VodCategoryEntries> listVodCategories =
        vodCategoryEntriesUtils.getDocumentsByKeyObjectIdValue("vodCategory", vodCategory);

    if (listVodCategories.size() < 2) Assert.fail("Not enough data");

    String vodIdOne = listVodCategories.get(0).getId();
    String vodIdTwo = listVodCategories.get(1).getId();

    UpdateOrderElement docOneOrder =
        UpdateOrderElement.newBuilder().setId(vodIdOne).setOrder(newOrder1).build();

    UpdateOrderElement docTwoOrder =
        UpdateOrderElement.newBuilder().setId(vodIdTwo).setOrder(newOrder2).build();

    List<UpdateOrderElement> listDocs = List.of(docOneOrder, docTwoOrder);
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.UpdateOrderResponse updateResponse =
        vodCategoryEntriesClient.updateOrder(vodCategory, listDocs);

    List<UpdateOrderElement> responseDocOne =
        updateResponse.getDocumentsList().stream()
            .filter(doc -> doc.getId().equals(vodIdOne))
            .collect(Collectors.toList());
    Assert.assertEquals(responseDocOne.size(), 1);
    Assert.assertEquals(newOrder1, responseDocOne.get(0).getOrder());

    List<UpdateOrderElement> responseDocTwo =
        updateResponse.getDocumentsList().stream()
            .filter(doc -> doc.getId().equals(vodIdTwo))
            .collect(Collectors.toList());
    Assert.assertEquals(responseDocTwo.size(), 1);
    Assert.assertEquals(newOrder2, responseDocTwo.get(0).getOrder());

    Assert.assertEquals(
        newOrder1, vodCategoryEntriesClient.getById(vodIdOne).getDocument().getOrder());
    Assert.assertEquals(
        newOrder2, vodCategoryEntriesClient.getById(vodIdTwo).getDocument().getOrder());
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: Some entries to update were not found")
  @Description("UpdateOrder - invalid id and not existed order number")
  @TmsLink("28501738")
  public void C28501738_TEST() {
    String testId = "58c4a2030da56df862000000";
    List<Integer> order = vodCategoryEntriesUtils.getDistinctListOfTheField("order", Integer.class);
    int validOrder = CommonUtils.listMissingIntegerFromListInOrder(order, 2).get(0);

    UpdateOrderElement docOrder =
        UpdateOrderElement.newBuilder().setId(testId).setOrder(validOrder).build();

    vodCategoryEntriesClient.updateOrder(testId, List.of(docOrder));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: Some entries to update were not found")
  @Description("UpdateOrder - invalid id and existed order number")
  @TmsLink("28501653")
  public void C28501653_TEST() {
    String testId = "58c4a2030da56df862000000";
    List<Integer> order = vodCategoryEntriesUtils.getDistinctListOfTheField("order", Integer.class);

    UpdateOrderElement docOrder =
        UpdateOrderElement.newBuilder().setId(testId).setOrder(order.get(1)).build();

    vodCategoryEntriesClient.updateOrder(testId, List.of(docOrder));
  }

  @Test(priority = 0)
  @Description("BulkDeleteVodCategoryEntries - delete series")
  @TmsLink("28501740")
  public void C28501740_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("series");
    String testVodCat = vodCategories.getVodCategory();
    List<VodCategoryEntries> listVodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    List<String> listSeries =
        listVodCategoryEntries.stream()
            .map(VodCategoryEntries::getSeries)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());
    Assert.assertFalse(listSeries.isEmpty());
    String testSeries = listSeries.get(0);
    List<String> listRemovedSeries = List.of(testSeries);

    List<VodCategoryEntry> documentsList =
        vodCategoryEntriesClient
            .bulkDeleteVodCategoryEntries(testVodCat, listRemovedSeries, Collections.emptyList())
            .getDocumentsList();
    Assert.assertEquals(testSeries, documentsList.get(0).getSeries());

    List<VodCategoryEntries> listVodCategoryEntriesAfterRemoving =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    Assert.assertEquals(
        listVodCategoryEntriesAfterRemoving.size() + 1, listVodCategoryEntries.size());
    long sizeTestSize =
        listVodCategoryEntriesAfterRemoving.stream()
            .filter(e -> e.getSeries().equals(testSeries))
            .count();
    Assert.assertEquals(sizeTestSize, 0);

    List<VodCategoryEntry> documentsListAfterAdd =
        vodCategoryEntriesClient
            .bulkAddVodCategoryEntries(testVodCat, listRemovedSeries, Collections.emptyList())
            .getDocumentsList();

    Assert.assertFalse(documentsListAfterAdd.isEmpty());
    VodCategoryEntry vodCategoryEntry = documentsListAfterAdd.get(0);

    Assert.assertEquals(vodCategoryEntry.getVodCategory(), testVodCat);
    Assert.assertEquals(vodCategoryEntry.getSeries(), testSeries);
  }

  @Test
  @Description("BulkDeleteVodCategoryEntries - delete episode")
  @TmsLink("28501741")
  public void C28501741_TEST() {
    // Iterate through VodCategoryEntries with episodes to find one whose vodCategory actually
    // exists
    VodCategoryEntries vodCategories = null;
    String testVodCat = null;
    Iterator<VodCategoryEntries> episodeIter =
        vodCategoryEntriesUtils.getExistsAndSizeNotZeroIterator("episode", 0);
    while (episodeIter.hasNext()) {
      VodCategoryEntries candidate = (VodCategoryEntries) episodeIter.next();
      if (!candidate.getVodCategory().isEmpty()
          && vodCategoryUtils.getDocumentById(candidate.getVodCategory()) != null) {
        vodCategories = candidate;
        testVodCat = candidate.getVodCategory();
        break;
      }
    }
    Assert.assertNotNull(vodCategories, "No VodCategoryEntry with a valid VodCategory found");
    LogUtils.logInfoMessage("Testing with vodCategory: " + testVodCat);
    List<VodCategoryEntries> listVodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    LogUtils.logInfoMessage("Found " + listVodCategoryEntries.size() + " entries");
    List<String> listEpisodes =
        listVodCategoryEntries.stream()
            .map(VodCategoryEntries::getEpisode)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());
    Assert.assertFalse(listEpisodes.isEmpty());
    String testEpisode = listEpisodes.get(0);
    List<String> listRemovedEpisode = List.of(testEpisode);
    LogUtils.logInfoMessage("listRemovedEpisode: " + listRemovedEpisode);
    List<VodCategoryEntry> documentsList =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), false)
            .bulkDeleteVodCategoryEntries(testVodCat, Collections.emptyList(), listRemovedEpisode)
            .getDocumentsList();
    Assert.assertEquals(testEpisode, documentsList.get(0).getEpisode());

    List<VodCategoryEntries> listVodCategoryEntriesAfterRemoving =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    Assert.assertEquals(
        listVodCategoryEntriesAfterRemoving.size() + 1, listVodCategoryEntries.size());
    long sizeTestSize =
        listVodCategoryEntriesAfterRemoving.stream()
            .filter(e -> e.getEpisode().equals(testEpisode))
            .count();
    Assert.assertEquals(sizeTestSize, 0);

    List<VodCategoryEntry> documentsListAfterAdd =
        vodCategoryEntriesClient
            .bulkAddVodCategoryEntries(testVodCat, Collections.emptyList(), listRemovedEpisode)
            .getDocumentsList();

    Assert.assertFalse(documentsListAfterAdd.isEmpty());
    VodCategoryEntry vodCategoryEntry = documentsListAfterAdd.get(0);

    Assert.assertEquals(vodCategoryEntry.getVodCategory(), testVodCat);
    Assert.assertEquals(vodCategoryEntry.getEpisode(), testEpisode);
    isBulkDeleteWorked = true;
  }

  @Test
  @Description("BulkAddVodCategoryEntries - verify the order episode after delete and add back")
  @TmsLink("28501748")
  public void C28501748_TEST() {
    // Iterate through VodCategoryEntries with episodes to find one whose vodCategory actually
    // exists
    VodCategoryEntries vodCategories = null;
    String testVodCat = null;
    Iterator<VodCategoryEntries> episodeIter =
        vodCategoryEntriesUtils.getExistsAndSizeNotZeroIterator("episode", 0);
    while (episodeIter.hasNext()) {
      VodCategoryEntries candidate = (VodCategoryEntries) episodeIter.next();
      if (!candidate.getVodCategory().isEmpty()
          && vodCategoryUtils.getDocumentById(candidate.getVodCategory()) != null) {
        vodCategories = candidate;
        testVodCat = candidate.getVodCategory();
        break;
      }
    }
    Assert.assertNotNull(vodCategories, "No VodCategoryEntry with a valid VodCategory found");
    List<VodCategoryEntries> listVodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    List<String> listEpisodes =
        listVodCategoryEntries.stream()
            .sorted(Comparator.comparingInt(VodCategoryEntries::getOrder))
            .map(VodCategoryEntries::getEpisode)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());
    Assert.assertFalse(listEpisodes.isEmpty());

    // expected list. Removed the last one and moved to the front
    List<String> expectedOrderedList = new ArrayList<>(listEpisodes);
    String testEpisode = expectedOrderedList.remove(expectedOrderedList.size() - 1);
    expectedOrderedList.add(0, testEpisode);

    List<String> listRemovedEpisode = List.of(testEpisode);

    List<VodCategoryEntry> documentsList =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), false)
            .bulkDeleteVodCategoryEntries(testVodCat, Collections.emptyList(), listRemovedEpisode)
            .getDocumentsList();
    Assert.assertEquals(documentsList.size(), 1);
    Assert.assertEquals(testEpisode, documentsList.get(0).getEpisode());

    List<VodCategoryEntry> documentsListAfterAdd =
        vodCategoryEntriesClient
            .bulkAddVodCategoryEntries(testVodCat, Collections.emptyList(), listRemovedEpisode)
            .getDocumentsList();

    Assert.assertFalse(documentsListAfterAdd.isEmpty());

    List<VodCategoryEntries> listVodCategoryEntriesAfter =
        vodCategoryEntriesUtils.getDocumentsByKeyObjectIdValue(
            "vodCategory", vodCategories.getVodCategory());
    List<String> listEpisodesAfter =
        listVodCategoryEntriesAfter.stream()
            .sorted(Comparator.comparingInt(VodCategoryEntries::getOrder))
            .map(VodCategoryEntries::getEpisode)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());

    Assert.assertEquals(listEpisodesAfter, expectedOrderedList);
  }

  @Test
  @Description("BulkAddVodCategoryEntries - verify the order series after delete and add back")
  @TmsLink("28501749")
  public void C28501749_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("series");
    String testVodCat = vodCategories.getVodCategory();
    List<VodCategoryEntries> listVodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", testVodCat);
    List<String> listSeries =
        listVodCategoryEntries.stream()
            .sorted(Comparator.comparingInt(VodCategoryEntries::getOrder))
            .map(VodCategoryEntries::getSeries)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());
    Assert.assertFalse(listSeries.isEmpty());

    // expected list. Removed the last one and moved to the front
    List<String> expectedOrderedList = new ArrayList<>(listSeries);
    String testSeries = expectedOrderedList.remove(expectedOrderedList.size() - 1);
    expectedOrderedList.add(0, testSeries);

    List<String> listRemovedSeries = List.of(testSeries);

    List<VodCategoryEntry> documentsList =
        new VodCategoryEntriesClient(grpcChannelManager.getChannel(), false)
            .bulkDeleteVodCategoryEntries(testVodCat, listRemovedSeries, Collections.emptyList())
            .getDocumentsList();
    Assert.assertEquals(documentsList.size(), 1);
    Assert.assertEquals(testSeries, documentsList.get(0).getSeries());

    List<VodCategoryEntry> documentsListAfterAdd =
        vodCategoryEntriesClient
            .bulkAddVodCategoryEntries(testVodCat, listRemovedSeries, Collections.emptyList())
            .getDocumentsList();

    Assert.assertFalse(documentsListAfterAdd.isEmpty());

    List<VodCategoryEntries> listVodCategoryEntriesAfter =
        vodCategoryEntriesUtils.getDocumentsByKeyObjectIdValue(
            "vodCategory", vodCategories.getVodCategory());
    List<String> listSeriesAfter =
        listVodCategoryEntriesAfter.stream()
            .sorted(Comparator.comparingInt(VodCategoryEntries::getOrder))
            .map(VodCategoryEntries::getSeries)
            .filter(e -> !e.isEmpty())
            .collect(Collectors.toList());

    Assert.assertEquals(listSeriesAfter, expectedOrderedList);
  }

  @Test(priority = 1)
  @Description("BulkAddVodCategoryEntries - delete and add series")
  @TmsLink("28501742")
  public void C28501742_TEST() {
    Assert.assertTrue(isBulkDeleteWorked);
  }

  @Test(priority = 2)
  @Description("BulkAddVodCategoryEntries - delete and add episode")
  @TmsLink("28501743")
  public void C28501743_TEST() {
    Assert.assertTrue(isBulkDeleteWorked);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: No entries to remove")
  @Description("BulkDeleteVodCategoryEntries - delete invalid series")
  @TmsLink("28501744")
  public void C28501744_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("series");
    List<String> listRemovedSeries = List.of("61a53d20c6bb840000000000");

    vodCategoryEntriesClient
        .bulkDeleteVodCategoryEntries(
            vodCategories.getVodCategory(), listRemovedSeries, Collections.emptyList())
        .getDocumentsList();
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: VodCategory not found")
  @Description("BulkDeleteVodCategoryEntries - delete invalid episode")
  @TmsLink("28501745")
  public void C28501745_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("episode");
    List<String> listRemovedEpisode = List.of("61a53d20c6bb840000000000");

    vodCategoryEntriesClient
        .bulkDeleteVodCategoryEntries(
            vodCategories.getVodCategory(), Collections.emptyList(), listRemovedEpisode)
        .getDocumentsList();
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: One or more Series not found")
  @Description("BulkAddVodCategoryEntries - add invalid series")
  @TmsLink("28501746")
  public void C28501746_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("series");
    List<String> listRemovedSeries = List.of("61a53d20c6bb840000000000");

    vodCategoryEntriesClient
        .bulkAddVodCategoryEntries(
            vodCategories.getVodCategory(), listRemovedSeries, Collections.emptyList())
        .getDocumentsList();
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: VodCategory not found")
  @Description("BulkAddVodCategoryEntries - add invalid episode")
  @TmsLink("28501747")
  public void C28501747_TEST() {
    VodCategoryEntries vodCategories = vodCategoryEntriesUtils.getExistsAndSizeNotZero("episode");
    List<String> listRemovedEpisode = List.of("61a53d20c6bb840000000000");

    vodCategoryEntriesClient
        .bulkAddVodCategoryEntries(
            vodCategories.getVodCategory(), Collections.emptyList(), listRemovedEpisode)
        .getDocumentsList();
  }

  @Test
  @Description("BulkAddVodCategoryEntries - add episodes and series")
  @TmsLink("28501750")
  public void C28501750_TEST() {
    int skip = new Random().nextInt(10);

    Iterator iterator =
        vodCategoryEntriesUtils.getExistsAndSizeNotZeroIterator("vodCategory", skip);
    VodCategoryEntries vodCategories = (VodCategoryEntries) iterator.next();
    String vodId = vodCategories.getVodCategory();
    LogUtils.logInfoMessage("Test vod category: " + vodId);
    List<String> listEpisodeIds =
        episodeUtils.getDocuments(2).stream()
            .map(e -> ((Episodes) e).getId())
            .collect(Collectors.toList());
    List<String> listSeriesIds =
        seriesUtils.getDocuments(2).stream()
            .map(e -> ((Series) e).getId())
            .collect(Collectors.toList());

    List<VodCategoryEntry> addedList =
        vodCategoryEntriesClient
            .bulkAddVodCategoryEntries(vodId, listSeriesIds, listEpisodeIds)
            .getDocumentsList();
    List<VodCategoryEntry> removeList =
        vodCategoryEntriesClient
            .bulkDeleteVodCategoryEntries(vodId, listSeriesIds, listEpisodeIds)
            .getDocumentsList();

    List<String> addedEpisodeIds =
        addedList.stream().map(VodCategoryEntry::getEpisode).collect(Collectors.toList());

    List<String> addedSeriesIds =
        addedList.stream().map(VodCategoryEntry::getSeries).collect(Collectors.toList());

    Assert.assertTrue(addedEpisodeIds.containsAll(listEpisodeIds));
    Assert.assertTrue(addedSeriesIds.containsAll(listSeriesIds));
    Assert.assertEquals(new HashSet<>(addedList), new HashSet<>(removeList));
  }

  @Test
  @Description("GetPopulatedEntriesByVodCategoryId - verify required fields")
  @TmsLink("28501751")
  public void C28501751_TEST() {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    String vodCategory = vodCategories.getVodCategory();
    List<VodCategoryEntries> vodCategoryEntriesList =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", vodCategory);

    SortOptions sortOptions =
        SortOptions.newBuilder().setField("sum_durations").setValue(1).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategory, List.of(sortOptions));

    List<PopulatedVodCategoryEntry> documentsList = response.getDocumentsList();
    Assert.assertEquals(vodCategoryEntriesList.size(), documentsList.size());
    Date dateNow = new Date();
    int sumDuration = 0;

    for (PopulatedVodCategoryEntry vodGrpc : documentsList) {
      VodCategoryEntries vodDb =
          vodCategoryEntriesList.stream()
              .filter(v -> v.getId().equals(vodGrpc.getId()))
              .findFirst()
              .get();
      Assert.assertEquals(vodGrpc.getId(), vodDb.getId());
      Assert.assertEquals(vodGrpc.getSeries().getId(), vodDb.getSeries());
      Assert.assertEquals(vodGrpc.getEpisode().getId(), vodDb.getEpisode());

      String episodeId = vodGrpc.getEpisode().getId();
      Episodes episode = episodeUtils.getDocumentById(episodeId);
      sumDuration = episode.getDuration() + sumDuration;

      if (!vodGrpc.getSeries().getId().isEmpty()) {
        String seriesId = vodGrpc.getSeries().getId();
        Series series = seriesUtils.getDocumentById(seriesId);
        Assert.assertEquals(series.getName(), vodGrpc.getSeries().getName());
        Assert.assertEquals(series.getType(), vodGrpc.getSeries().getType());
        Assert.assertEquals(vodGrpc.getSeries().getSubCategory(), series.getSubCategory());
        Assert.assertEquals(vodGrpc.getSeries().getGenre(), series.getGenre());
        Assert.assertEquals(vodGrpc.getSeries().getSubGenre(), series.getSubGenre());
        Assert.assertEquals(vodGrpc.getSeries().getCategory(), series.getCategory());
      }

      Assert.assertEquals(episode.getAdPodsDuration(), vodGrpc.getEpisode().getAdPodsDuration());

      List<String> listClips =
          episode.getSources().stream().map(Source::getClip).collect(Collectors.toList());
      List<tv.pluto.mongo.entities.clips.Clips> listMongoDbClips =
          clipsUtils.getDocumentsByIds(listClips);

      // allClipsReady
      boolean isContentStatus =
          listMongoDbClips.stream().allMatch(clip -> clip.getContentStatus().equals("ready"));
      tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.Episode episodeGrpc =
          vodGrpc.getEpisode();
      Assert.assertEquals(isContentStatus, episodeGrpc.getAllClipsReady());

      // isAvailableNow
      List<Window> linearWindow = episode.getAvailabilityWindows().getLinear();

      if (linearWindow.isEmpty()) Assert.assertFalse(episodeGrpc.getIsAvailableNow());
      else {
        boolean isAvailable =
            linearWindow.stream()
                .anyMatch(
                    linear ->
                        linear.getStartDate().before(dateNow)
                            && linear.getEndDate().after(dateNow));
        Assert.assertTrue(isAvailable);
      }

      Assert.assertEquals(episodeGrpc.getName(), episode.getName());
      Assert.assertEquals(episodeGrpc.getSeason(), episode.getSeason());
      Assert.assertEquals(episodeGrpc.getNumber(), episode.getNumber());
      Assert.assertEquals(episodeGrpc.getDuration(), episode.getDuration());
      Assert.assertEquals(episodeGrpc.getSubCategory(), episode.getSubCategory());
      Assert.assertEquals(episodeGrpc.getGenre(), episode.getGenre());
      Assert.assertEquals(episodeGrpc.getSubGenre(), episode.getSubGenre());
      Assert.assertEquals(episodeGrpc.getCategory(), episode.getCategory());

      // hasUniqueProvider and hasMixedProviderWith
      long countClipsInSources =
          episode.getSources().stream().filter(s -> !s.getClip().isEmpty()).count();

      if (countClipsInSources == 0) Assert.assertFalse(episodeGrpc.getHasUniqueProvider());
      else Assert.assertTrue(episodeGrpc.getHasUniqueProvider());

      if (episode.getIsFeed() && countClipsInSources == 0)
        Assert.assertFalse(episodeGrpc.getHasMixedProviderWith());

      // hasClipWithEmptySources
      boolean hasClipWithEmptySources =
          listMongoDbClips.stream().anyMatch(clip -> clip.getSources().size() == 0);
      Assert.assertEquals(hasClipWithEmptySources, episodeGrpc.getHasClipWithEmptySources());
    }
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by order")
  @TmsLink("28501752")
  public void C28501752_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions = SortOptions.newBuilder().setField("order").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<Integer> listOrdersGrpc =
        response.getDocumentsList().stream().map(v -> v.getOrder()).collect(Collectors.toList());
    List<Integer> sortedOrder = new ArrayList<>(listOrdersGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listOrdersGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by categories")
  @TmsLink("28501753")
  public void C28501753_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<String> listOrdersGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getVodCategory())
            .collect(Collectors.toList());
    List<String> sortedOrder = new ArrayList<>(listOrdersGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listOrdersGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by series.type")
  @TmsLink("28501754")
  public void C28501754_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<String> listGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getSeries().getType())
            .collect(Collectors.toList());
    List<String> sortedOrder = new ArrayList<>(listGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by series.name")
  @TmsLink("28501760")
  public void C28501760_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<String> listGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getSeries().getName())
            .collect(Collectors.toList());
    List<String> sortedOrder = new ArrayList<>(listGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by series.seasonCount")
  @TmsLink("28501756")
  public void C28501756_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<Integer> listGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getSeries().getSeasonCount())
            .collect(Collectors.toList());
    List<Integer> sortedOrder = new ArrayList<>(listGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by series.episodeCount")
  @TmsLink("28501757")
  public void C28501757_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<Integer> listGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getSeries().getEpisodeCount())
            .collect(Collectors.toList());
    List<Integer> sortedOrder = new ArrayList<>(listGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listGrpc, sortedOrder);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetPopulatedEntriesByVodCategoryId - sort by series.name")
  @TmsLink("28501755")
  public void C28501755_TEST(int sort) {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("categories").setValue(sort).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            null, 0, vodCategories.getVodCategory(), List.of(sortOptions));

    List<String> listGrpc =
        response.getDocumentsList().stream()
            .map(v -> v.getSeries().getName())
            .collect(Collectors.toList());
    List<String> sortedOrder = new ArrayList<>(listGrpc);

    if (sort == 1) Collections.sort(sortedOrder);
    else sortedOrder.sort(Collections.reverseOrder());

    Assert.assertEquals(listGrpc, sortedOrder);
  }

  @Test
  @Description("GetPopulatedEntriesByVodCategoryId - limit and offset")
  @TmsLink("28501764")
  public void C28501764_TEST() {
    int limit = 1;
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            limit, 0, vodCategories.getVodCategory(), Collections.emptyList());

    Assert.assertEquals(response.getDocumentsCount(), limit);
    Assert.assertEquals(response.getDocumentsList().size(), limit);
    Assert.assertEquals(response.getDocumentsCount(), response.getDocumentsList().size());
  }

  @Test
  @Description("GetPopulatedEntriesByVodCategoryId - vodCategoryEntriesCount for episodes")
  @TmsLink("28501765")
  public void C28501765_TEST() {
    int limit = 100;
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZero("vodCategory");
    String vodCategory = vodCategories.getVodCategory();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            limit, 0, vodCategory, Collections.emptyList());

    Assert.assertTrue(limit >= response.getDocumentsCount());
    Assert.assertTrue(limit >= response.getDocumentsList().size());
    Assert.assertEquals(response.getDocumentsCount(), response.getDocumentsList().size());
  }

  @Test
  @Description("GetPopulatedEntriesByVodCategoryId - count AdPods for episodes")
  @TmsLink("28501769")
  public void C28501769_TEST() {
    Iterator<VodCategoryEntries> iteratorVodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZeroIterator("vodCategory", 7);

    Assert.assertTrue(iteratorVodCategories.hasNext(), "No VodCategoryEntries found.");

    String vodCategory = iteratorVodCategories.next().getVodCategory();
    SortOptions sortOptions =
        SortOptions.newBuilder().setField("sum_durations").setValue(1).build();

    GetPopulatedEntriesByVodCategoryIdResponse response =
        vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
            5, 0, vodCategory, List.of(sortOptions));

    Assert.assertNotNull(response, "Response is null.");
    Assert.assertFalse(response.getDocumentsList().isEmpty(), "No documents found in response.");

    for (PopulatedVodCategoryEntry entry : response.getDocumentsList()) {
      String episodeId = entry.getEpisode().getId();
      Episodes episode = episodeUtils.getDocumentById(episodeId);
      Assert.assertNotNull(episode, "Episode not found for ID: " + episodeId);

      List<String> listClips =
          episode.getSources().stream().map(Source::getClip).collect(Collectors.toList());

      List<Clips> documentsByIds = clipsUtils.getDocumentsByIds(listClips);
      Assert.assertNotNull(documentsByIds, "Clips not found for episode ID: " + episodeId);

      List<String> filteredClipIds =
          documentsByIds.stream()
              .filter(
                  clip ->
                      !(clip.getPromotional()
                          || clip.getProgrammingType().equals("Pluto TV Systems")))
              .map(Clips::getId)
              .collect(Collectors.toList());

      long lengthOfAdPods =
          episode.getSources().stream()
              .filter(source -> filteredClipIds.contains(source.getClip()))
              .mapToLong(source -> source.getAdPods().size())
              .sum();

      Assert.assertEquals(
          lengthOfAdPods,
          entry.getEpisode().getAdPods(),
          "AdPods length mismatch for episode ID: " + episodeId);
    }
  }

  @Test
  @Description("GetPopulatedEntriesByVodCategoryId - promotional adpods")
  @TmsLink("28501768")
  public void C28501768_TEST() {
    Iterator<VodCategoryEntries> iteratorVodCategories =
        vodCategoryEntriesUtils.getExistsAndSizeNotZeroIterator("vodCategory", 7);
    int total = 0;
    while (total <= 5) {
      String vodCategory = iteratorVodCategories.next().getVodCategory();
      SortOptions sortOptions =
          SortOptions.newBuilder().setField("sum_durations").setValue(1).build();

      GetPopulatedEntriesByVodCategoryIdResponse response =
          vodCategoryEntriesClient.getPopulatedEntriesByVodCategoryId(
              50, 0, vodCategory, List.of(sortOptions));

      for (PopulatedVodCategoryEntry entry : response.getDocumentsList()) {
        boolean promotionalAdpods = entry.getEpisode().getPromotionalAdpods();

        if (entry.getEpisode().getAdPods() == 0) Assert.assertFalse(promotionalAdpods);
      }
      total++;
    }
  }

  @Test
  @Description("GetEntriesDurationsSumByVodCategoryId - happy path")
  @TmsLink("28501775")
  public void C28501775_TEST() {
    VodCategoryEntries randomVodCategoryEntries = vodCategoryEntriesUtils.getRandomDocument();
    String id = randomVodCategoryEntries.getVodCategory();

    int sumDurationsEpisodes = vodCategoryEntriesUtils.getSumEpisodesFromVodCategory(id);
    int sumDurationsEpisodeSeries = vodCategoryEntriesUtils.getSumEpisodesFromVodCategorySeries(id);
    int dbTotalDuration = sumDurationsEpisodes + sumDurationsEpisodeSeries;

    long durationGrpc =
        vodCategoryEntriesClient.getEntriesDurationsSumByVodCategoryId(id).getDuration();

    Assert.assertEquals(durationGrpc, dbTotalDuration);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("GetEntriesDurationsSumByVodCategoryId - INTERNAL error")
  @TmsLink("28501776")
  public void C28501776_TEST() {
    vodCategoryEntriesClient.getEntriesDurationsSumByVodCategoryId("DAL");
  }

  @Test
  @Description("GetVodCategoryEntriesByVodCategoryIds - happy path")
  @TmsLink("28501772")
  public void C28501772_TEST() {
    GetAllPagedResponse responseGetAllPaged =
        vodCategoryEntriesClient.getAllPaged(2, 0, null, null, null);
    List<VodCategoryEntry> listVodcategory = responseGetAllPaged.getDocumentsList();
    List<String> listVodIds =
        listVodcategory.stream().map(v -> v.getVodCategory()).collect(Collectors.toList());

    List<VodCategoryEntry> responseVodList =
        vodCategoryEntriesClient
            .getVodCategoryEntriesByVodCategoryIds(listVodIds)
            .getDocumentsList();
    List<String> listIdResponse =
        responseVodList.stream().map(v -> v.getId()).collect(Collectors.toList());
    List<VodCategoryEntries> grpcGetVodCategoryEntriesByVodCategoryIds =
        vodCategoryUtils.mapGrpcObjectsToPojo(responseVodList, VodCategoryEntries.class);
    grpcGetVodCategoryEntriesByVodCategoryIds.sort(Comparator.comparing(VodCategoryEntries::getId));

    List<VodCategoryEntries> listVodCategoryMango =
        vodCategoryEntriesUtils.getDocumentsByIds(listIdResponse);
    listVodCategoryMango.sort(Comparator.comparing(VodCategoryEntries::getId));

    Assert.assertFalse(listVodCategoryMango.isEmpty());
    Assert.assertEquals(listVodCategoryMango, grpcGetVodCategoryEntriesByVodCategoryIds);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetVodCategoryEntriesByVodCategoryIds - invalid id")
  @TmsLink("28501773")
  public void C28501773_TEST() {
    vodCategoryEntriesClient.getVodCategoryEntriesByVodCategoryIds(List.of(INVALID_ID_VALUE));
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("GetVodCategoryEntriesByVodCategoryIds - invalid format id")
  @TmsLink("28501774")
  public void C28501774_TEST() {
    vodCategoryEntriesClient.getVodCategoryEntriesByVodCategoryIds(List.of("test"));
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetFilteredVodCategoryEntries - invalid seriesName")
  @TmsLink("28501778")
  public void C28501778_TEST() {
    vodCategoryEntriesClient.getFilteredVodCategoryEntries(
        1, 0, "testData", "td", "td", "td", "td", "td");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - SeriesType & SeriesName")
  @TmsLink("28501777")
  public void C28501777_TEST() {

    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);

    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();

    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    // gRPC client call using series name and type
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredSeriesVodCategoryEntries(
                1, 0, mongoSeries.getName(), mongoSeries.getType());

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);
    String grpcSeriesId = grpcEntry.getSeries().getId();
    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getName(), grpcEntry.getSeries().getName(), "Series name should match.");
    Assert.assertEquals(
        relatedSeries.getType(), grpcEntry.getSeries().getType(), "Series type should match.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Series and Episodes")
  @TmsLink("28501779")
  public void C28501779_TEST() {

    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheFieldInSeries("series", true);

    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();

    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    // gRPC client call using filter
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredSeriesAndEpisodes(
                1000,
                0,
                mongoSeries.getGenre(),
                mongoSeries.getCategory(),
                mongoSeries.getSubCategory(),
                mongoSeries.getSubGenre(),
                mongoSeries.getRating(),
                mongoSeries.getMetadataLanguage());

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().stream()
            .filter(v -> !v.getSeries().getId().isEmpty())
            .findFirst()
            .orElseThrow(() -> new AssertionError("No entry with series found in gRPC response."));

    String grpcSeriesId = grpcEntry.getSeries().getId();

    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getGenre(), grpcEntry.getSeries().getGenre(), "genre should match.");
    Assert.assertEquals(
        relatedSeries.getCategory(), grpcEntry.getSeries().getCategory(), "Category should match.");
    Assert.assertEquals(
        relatedSeries.getSubCategory(),
        grpcEntry.getSeries().getSubCategory(),
        "SubCategory should match.");
    Assert.assertEquals(
        relatedSeries.getSubGenre(), grpcEntry.getSeries().getSubGenre(), "SubGenre should match.");
    Assert.assertEquals(
        relatedSeries.getRating(), grpcEntry.getSeries().getRating(), "Rating  should match.");
    Assert.assertEquals(
        relatedSeries.getMetadataLanguage(),
        grpcEntry.getSeries().getMetadataLanguage(),
        "Language should match.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - AvailabilityWindows")
  @TmsLink("28501780")
  public void C28501780_TEST() {
    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheFieldInSeries("series", true);

    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();

    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    // gRPC client call using filter
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredSeriesVodCategoryEntries(
                1, 0, mongoSeries.getName(), mongoSeries.getType());

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);
    String grpcSeriesId = grpcEntry.getSeries().getId();
    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);
    // isAvailableNow
    List<Window> avodWindow = relatedSeries.getAvailabilityWindows().getAvod();

    Instant dateNow = Instant.now().minusSeconds(1);
    if (avodWindow.isEmpty()) {
      Assert.assertEquals(grpcEntry.getSeries().getAvailabilityWindows().getAVODCount(), 0);
    } else {
      boolean isAvailable =
          avodWindow.stream()
              .anyMatch(
                  linear ->
                      linear.getStartDate().toInstant().isBefore(dateNow)
                          && linear.getEndDate().toInstant().isAfter(dateNow));
      Assert.assertTrue(isAvailable);
    }

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getGenre(), grpcEntry.getSeries().getGenre(), "genre should match.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Series&Episodes Projection")
  @TmsLink("28501781")
  public void C28501781_TEST() {

    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);
    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();
    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    // Projection fields for series and episodes
    List<String> seriesFields = Arrays.asList("id", "name", "availability_windows._a_v_o_d");
    List<String> episodeFields = List.of("name");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredProjectionSeriesAndEpisodes(
                1, mongoSeries.getName(), seriesFields, episodeFields);

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);
    String grpcSeriesId = grpcEntry.getSeries().getId();
    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getName(), grpcEntry.getSeries().getName(), "Series name should match.");

    Assert.assertFalse(grpcEntry.getVodCategory().isEmpty(), "Vod Category should not be empty.");

    Assert.assertFalse(grpcEntry.getId().isEmpty(), "ID should not be empty.");

    Assert.assertTrue(
        grpcEntry.getOrder() > 0, "Order should have a valid value (greater than 0).");

    Assert.assertFalse(
        grpcEntry.getCreatedAt().isEmpty(), "Created at timestamp should not be empty.");

    Assert.assertFalse(
        grpcEntry.getUpdatedAt().isEmpty(), "Updated at timestamp should not be empty.");

    Assert.assertTrue(
        grpcEntry.getSeries().getType().isEmpty(),
        "Series type should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getMetadataLanguage().isEmpty(),
        "Metadata language should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getCategory().isEmpty(),
        "Category should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getSubCategory().isEmpty(),
        "Sub-category should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getGenre().isEmpty(), "Genre should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getSubGenre().isEmpty(),
        "Sub-genre should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getRating().isEmpty(), "Rating should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getTagsList().isEmpty(), "Tags should be an empty list if present.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Series&Episodes Incorrect Projection")
  @TmsLink("28501782")
  public void C28501782_TEST() {

    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);
    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();
    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    List<String> seriesFields = List.of("*****");
    List<String> episodeFields = List.of("*****");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredProjectionSeriesAndEpisodes(
                1, mongoSeries.getName(), seriesFields, episodeFields);

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);

    Assert.assertTrue(
        grpcEntry.getSeries().getId().isEmpty(), "Related series should not be null for entry: ");
    Assert.assertTrue(grpcEntry.getSeries().getName().isEmpty(), "Series name should not be empty");
    Assert.assertTrue(grpcEntry.getEpisode().getId().isEmpty(), "Series should not be empty");

    Assert.assertFalse(grpcEntry.getVodCategory().isEmpty(), "Vod Category should not be empty.");

    Assert.assertFalse(grpcEntry.getId().isEmpty(), "ID should not be empty.");

    Assert.assertTrue(
        grpcEntry.getOrder() > 0, "Order should have a valid value (greater than 0).");

    Assert.assertFalse(
        grpcEntry.getCreatedAt().isEmpty(), "Created at timestamp should not be empty.");

    Assert.assertFalse(
        grpcEntry.getUpdatedAt().isEmpty(), "Updated at timestamp should not be empty.");

    Assert.assertTrue(
        grpcEntry.getSeries().getType().isEmpty(),
        "Series type should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getMetadataLanguage().isEmpty(),
        "Metadata language should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getCategory().isEmpty(),
        "Category should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getSubCategory().isEmpty(),
        "Sub-category should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getGenre().isEmpty(), "Genre should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getSubGenre().isEmpty(),
        "Sub-genre should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getRating().isEmpty(), "Rating should be an empty list if present.");
    Assert.assertTrue(
        grpcEntry.getSeries().getTagsList().isEmpty(), "Tags should be an empty list if present.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Series&Episodes NO Projection")
  @TmsLink("28501783")
  public void C28501783_TEST() {
    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);
    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();
    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    // Projection fields for series and episodes
    List<String> seriesFields = List.of();
    List<String> episodeFields = List.of();

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredProjectionSeriesAndEpisodes(
                1, mongoSeries.getName(), seriesFields, episodeFields);

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);
    String grpcSeriesId = grpcEntry.getSeries().getId();
    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);
    VodCategoryEntries vodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentById(grpcEntry.getId());

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getName(), grpcEntry.getSeries().getName(), "Series name should match.");
    Assert.assertEquals(relatedSeries.getId(), grpcSeriesId, "Series name should match.");
    Assert.assertEquals(
        vodCategoryEntries.getVodCategory(),
        grpcEntry.getVodCategory(),
        "Vod Category should match.");
    Assert.assertEquals(vodCategoryEntries.getOrder(), grpcEntry.getOrder(), "Order should match.");
    Assert.assertEquals(
        vodCategoryEntries.getCreatedAt().toInstant(ZoneOffset.UTC).toString(),
        grpcEntry.getCreatedAt(),
        "CreatedAt should match.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Series Projection Only")
  @TmsLink("28501784")
  public void C28501784_TEST() {
    VodCategoryEntries vodCategoryEntriesWithSeriesIds =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);
    Assert.assertFalse(
        vodCategoryEntriesWithSeriesIds.getSeries().isEmpty(),
        "No VodCategoryEntries with series IDs found.");

    String seriesId = vodCategoryEntriesWithSeriesIds.getSeries();
    Series mongoSeries = seriesUtils.getDocumentById(seriesId);
    Assert.assertNotNull(mongoSeries, "Mongo Series should not be null.");

    List<String> seriesFields = Arrays.asList("id", "name", "availability_windows._a_v_o_d");
    List<String> episodeFields = List.of();

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.GetFilteredVodCategoryEntriesResponse
        grpcResponse =
            vodCategoryEntriesClient.getFilteredProjectionSeriesAndEpisodes(
                1, mongoSeries.getName(), seriesFields, episodeFields);

    Assert.assertFalse(
        grpcResponse.getDocumentsList().isEmpty(), "gRPC response should contain documents.");

    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredVodCategoryEntry grpcEntry =
        grpcResponse.getDocumentsList().get(0);
    String grpcSeriesId = grpcEntry.getSeries().getId();
    Series relatedSeries = seriesUtils.getDocumentById(grpcSeriesId);

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getName(), grpcEntry.getSeries().getName(), "Series name should match.");

    Assert.assertFalse(grpcEntry.getVodCategory().isEmpty(), "Vod Category should not be empty.");

    Assert.assertFalse(grpcEntry.getId().isEmpty(), "ID should not be empty.");
    tv.pluto.ip.dal.vodcategoryentry.VodCategoryEntries.FilteredEpisode episode =
        grpcEntry.getEpisode();
    Assert.assertTrue(episode.getId().isEmpty());
    Assert.assertTrue(episode.getName().isEmpty());
    Assert.assertTrue(episode.getCategory().isEmpty());

    VodCategoryEntries vodCategoryEntries =
        vodCategoryEntriesUtils.getDocumentById(grpcEntry.getId());

    Assert.assertNotNull(
        relatedSeries, "Related series should not be null for entry: " + grpcEntry.getId());
    Assert.assertEquals(
        relatedSeries.getName(), grpcEntry.getSeries().getName(), "Series name should match.");
    Assert.assertEquals(relatedSeries.getId(), grpcSeriesId, "Series name should match.");
    Assert.assertEquals(
        vodCategoryEntries.getVodCategory(),
        grpcEntry.getVodCategory(),
        "Vod Category should match.");
    Assert.assertEquals(vodCategoryEntries.getOrder(), grpcEntry.getOrder(), "Order should match.");
    Assert.assertEquals(
        vodCategoryEntries.getCreatedAt().toInstant(ZoneOffset.UTC).toString(),
        grpcEntry.getCreatedAt(),
        "CreatedAt should match.");
  }

  @Test
  @Description("GetFilteredVodCategoryEntries - Projection NOT_FOUND")
  @TmsLink("28501785")
  public void C28501785_TEST() {
    try {

      vodCategoryEntriesClient.getFilteredProjectionSeriesAndEpisodes(
          1, "gggg", List.of(), List.of());
      Assert.fail("Expected StatusRuntimeException was not thrown.");
    } catch (StatusRuntimeException e) {

      Assert.assertEquals(e.getStatus().getCode(), Status.NOT_FOUND.getCode());
      Assert.assertEquals(
          e.getMessage(), "NOT_FOUND: VodCategoryEntry documents for requested IDs not found");
    }
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: The episode id .* is already associated to the vod category id .* - order 99.")
  @Description(
      "CreateRequest - Attempt to create a duplicate VodCategoryEntries with the same Episode.")
  @TmsLink("28501786")
  public void C28501786_TEST() {
    String randomObjectId = new ObjectId().toString();
    int order = 99;

    VodCategoryEntry vodCategoryEntry =
        VodCategoryEntry.newBuilder()
            .setEpisode(randomObjectId)
            .setOrder(order)
            .setVodCategory(randomObjectId)
            .build();

    LogUtils.logInfoMessage("Created VodCategoryEntry id: " + vodCategoryEntry.getVodCategory());

    new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true)
        .getCreateRequest(vodCategoryEntry);

    new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true)
        .getCreateRequest(vodCategoryEntry);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: The series id .* is already associated to the vod category id .* - order 99.")
  @Description(
      "CreateRequest - Attempt to create a duplicate VodCategoryEntries with the same Series.")
  @TmsLink("28501787")
  public void C28501787_TEST() {
    String randomObjectId = new ObjectId().toString();
    int order = 99;

    VodCategoryEntry vodCategoryEntry =
        VodCategoryEntry.newBuilder()
            .setSeries(randomObjectId)
            .setOrder(order)
            .setVodCategory(randomObjectId)
            .build();

    LogUtils.logInfoMessage("Created VodCategoryEntry id: " + vodCategoryEntry.getVodCategory());

    new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true)
        .getCreateRequest(vodCategoryEntry);

    new VodCategoryEntriesClient(grpcChannelManager.getChannel(), true)
        .getCreateRequest(vodCategoryEntry);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: All Series and Episodes already exist in this VodCategory")
  @Description(
      "BulkAddVodCategoryEntries - Attempt to add the same Series and Episodes to the same VodCategory.")
  @TmsLink("28501788")
  public void C28501788_TEST() {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);

    String vodId = vodCategories.getVodCategory();

    LogUtils.logInfoMessage("Test vod category: " + vodId);

    List<String> listEpisodeIds =
        episodeUtils.getRandomDocuments(2).stream().map(e -> ((Episodes) e).getId()).toList();
    List<String> listSeriesIds =
        seriesUtils.getRandomDocuments(2).stream().map(e -> ((Series) e).getId()).toList();

    vodCategoryEntriesClient.bulkAddVodCategoryEntries(vodId, listSeriesIds, listEpisodeIds);

    vodCategoryEntriesClient.bulkAddVodCategoryEntries(vodId, listSeriesIds, listEpisodeIds);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: The following items cannot be associated multiple times: episode id .* on vod category id .*")
  @Description(
      "BulkAddVodCategoryEntries - Attempt to add the same Episode twice to the same VodCategory.")
  @TmsLink("28501789")
  public void C28501789_TEST() {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);

    String vodId = vodCategories.getVodCategory();

    LogUtils.logInfoMessage("Test vod category: " + vodId);

    String episodeId =
        episodeUtils.getRandomDocuments(1).stream()
            .map(e -> ((Episodes) e).getId())
            .findFirst()
            .orElse(null);

    List<String> duplicateEpisodesList = Arrays.asList(episodeId, episodeId);

    List<String> listSeriesIds =
        seriesUtils.getRandomDocuments(2).stream().map(e -> ((Series) e).getId()).toList();

    vodCategoryEntriesClient.bulkAddVodCategoryEntries(vodId, listSeriesIds, duplicateEpisodesList);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: The following items cannot be associated multiple times: series id .* on vod category id .*")
  @Description(
      "BulkAddVodCategoryEntries - Attempt to add the same Series twice to the same VodCategory.")
  @TmsLink("28501790")
  public void C28501790_TEST() {
    VodCategoryEntries vodCategories =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("series", true);

    String vodId = vodCategories.getVodCategory();

    LogUtils.logInfoMessage("Test vod category: " + vodId);

    List<String> listEpisodeIds =
        episodeUtils.getRandomDocuments(2).stream().map(e -> ((Episodes) e).getId()).toList();

    String seriesId =
        seriesUtils.getRandomDocuments(1).stream()
            .map(e -> ((Series) e).getId())
            .findFirst()
            .orElse(null);

    List<String> duplicateSeriesList = Arrays.asList(seriesId, seriesId);

    vodCategoryEntriesClient.bulkAddVodCategoryEntries(vodId, duplicateSeriesList, listEpisodeIds);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: VodCategory not found")
  @Description("BulkAddVodCategoryEntries - Attempt to add data to a non-existent vod category.")
  @TmsLink("28501791")
  public void C28501791_TEST() {

    String nonExistentVodCategoryId = new ObjectId().toString();

    vodCategoryEntriesClient.bulkAddVodCategoryEntries(
        nonExistentVodCategoryId, Collections.emptyList(), Collections.emptyList());
  }
}
