/*
 * (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 com.mongodb.client.model.Collation;
import com.mongodb.client.result.InsertManyResult;
import com.plutotv.test.lib.LogUtils;
import io.grpc.ManagedChannel;
import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.Issue;
import io.qameta.allure.TmsLink;
import java.lang.reflect.InvocationTargetException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.stream.Collectors;
import org.bson.BsonValue;
import org.bson.Document;
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 tv.pluto.core.BaseTest;
import tv.pluto.grpc.main_categories.MainCategoriesClient;
import tv.pluto.ip.dal.maincategories.MainCategories.Filter;
import tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse;
import tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort;
import tv.pluto.ip.dal.maincategories.MainCategories.Id;
import tv.pluto.ip.dal.maincategories.MainCategories.MainCategory;
import tv.pluto.mongo.dto.ContentFeedQuery;
import tv.pluto.mongo.dto.DocumentQuery;
import tv.pluto.mongo.entities.channels.Channels;
import tv.pluto.mongo.entities.common.Category;
import tv.pluto.mongo.entities.maincategories.MainCategories;
import tv.pluto.mongo.entities.vod.VodCategories;
import tv.pluto.mongo.entities.vodcategories.Categories;
import tv.pluto.mongo.utils.ChannelsUtils;
import tv.pluto.mongo.utils.MainCategoriesUtils;
import tv.pluto.mongo.utils.VodCategoryUtils;
import tv.pluto.utils.CommonUtils;

public class MainCategoriesTestSuite extends BaseTest {
  private MainCategoriesClient mainCategoriesClient;
  private MainCategoriesClient mainCategoriesClientAuth;
  private MainCategoriesUtils mainCategoriesUtils;
  private VodCategoryUtils vodCategoryUtils;
  private ChannelsUtils channelsUtils;
  private static final String NOT_FOUND_CATEGORIES =
      "NOT_FOUND: MainCategories documents for requested ID not found";
  private static final String NOT_FOUND_IDS_CATEGORIES =
      "NOT_FOUND: MainCategories documents for requested IDs not found";
  private static final String CATEGORY_ID = "categories.catId";

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    mainCategoriesClient = new MainCategoriesClient(grpcChannelManager.getChannel(), false);
    mainCategoriesClientAuth = new MainCategoriesClient(grpcChannelManager.getChannel(), true);
    mainCategoriesUtils = new MainCategoriesUtils();
    vodCategoryUtils = new VodCategoryUtils();
    channelsUtils = new ChannelsUtils();
  }

  @Test
  @Description("GetDocumentsUpdatedBetweenDates - Time period for which there is a application")
  @TmsLink("28501055")
  public void C28501055_TEST() {

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

    List<MainCategories> mongoMainCategories =
        mainCategoriesUtils.getDocumentsForContentFeeds(contentFeedQuery);
    List<MainCategories> grpcMainCategories = new ArrayList<>();

    Iterator<tv.pluto.ip.dal.maincategories.MainCategories.MainCategory> mainCategories =
        mainCategoriesClient.getDocumentsUpdatedBetweenDates(
            mainCategoriesUtils.updatedAtMinString, mainCategoriesUtils.updatedAtMaxString);

    while (mainCategories.hasNext()) {
      grpcMainCategories.add(
          mainCategoriesUtils.mapGrpcObjectToPojo(mainCategories.next(), MainCategories.class));
    }

    mongoMainCategories.sort(Comparator.comparing(MainCategories::getId));
    grpcMainCategories.sort(Comparator.comparing(MainCategories::getId));

    List<String> mongoIds = mongoMainCategories.stream().map(MainCategories::getId).toList();
    List<String> grpcIds = grpcMainCategories.stream().map(MainCategories::getId).toList();

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

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("GetDocumentsUpdatedBetweenDates - Time period without application")
  @TmsLink("28501056")
  public void C28501056_TEST() {
    mainCategoriesClient.getDocumentsUpdatedBetweenDates(failStartDateTime, failEndDateTime).next();
  }

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

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

  @Test
  @Description("CFeedsSyncAllIds- stream returns CFEEDS stream of Main Categories ids")
  @TmsLink("28501067")
  public void C28501067_TEST() {
    Iterator<Object> cFeedsSyncAllIds =
        mainCategoriesClient.getCFeedsResponse(null, null, null, "cFeedsSyncAllIds");
    List<String> listCFeedsSyncAllIds =
        CommonUtils.iteratorToList(cFeedsSyncAllIds).stream()
            .map(o -> ((Id) o).getId())
            .sorted()
            .collect(Collectors.toList());
    List<String> mongoIds =
        mainCategoriesUtils.getListOfAllObjects().stream()
            .map(cat -> ((MainCategories) cat).getId())
            .sorted()
            .collect(Collectors.toList());

    Assert.assertTrue(listCFeedsSyncAllIds.size() > 0);
    Assert.assertTrue(CommonUtils.isTwoListsEqual(listCFeedsSyncAllIds, mongoIds));
  }

  @Test
  @Description("cFeedsSyncDocuments - last_run_at")
  @TmsLink("28501068")
  public void C28501068_TEST() {
    MainCategories categories = mainCategoriesUtils.getRandomDocument();
    Iterator<Object> cFeedsSyncAllIds =
        mainCategoriesClient.getCFeedsResponse(
            null, categories.getUpdatedAt() + "Z", null, "cFeedsSyncDocuments");
    List<?> grpcMainCategory = CommonUtils.iteratorToList(cFeedsSyncAllIds);
    List<MainCategories> grpcMainCategories =
        mainCategoriesUtils.mapGrpcObjectsToPojo(grpcMainCategory, MainCategories.class);

    List<MainCategories> mongoListCategories =
        mainCategoriesUtils.getDocumentsForFeedsSyncStartTime(categories.getUpdatedAt()).stream()
            .map(o -> ((MainCategories) o))
            .collect(Collectors.toList());

    grpcMainCategories.sort(Comparator.comparing(MainCategories::getId));
    mongoListCategories.sort(Comparator.comparing(MainCategories::getId));

    Assert.assertTrue(grpcMainCategories.size() > 0);
    Assert.assertEquals(grpcMainCategories, mongoListCategories);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("cFeedsSyncDocuments - last_run_at future time")
  @TmsLink("28501069")
  public void C28501069_TEST() {
    String futureTime = CommonUtils.localDateTimeStringPlusDays(10);
    mainCategoriesClient.getCFeedsResponse(null, futureTime, null, "cFeedsSyncDocuments").next();
  }

  @Test
  @Description("Create - mainCategory")
  @TmsLink("28501070")
  public void C28501070_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName())
            .setSlug(doc.getSlug())
            .setActiveRegion(doc.getActiveRegion())
            .build();

    MainCategory response = mainCategoriesClientAuth.createRequest(mainRequest).getDocument();

    Assert.assertEquals(response.getName(), doc.getName());
    Assert.assertTrue(response.getSlug().contains(doc.getSlug()));
    Assert.assertEquals(response.getActiveRegion(), doc.getActiveRegion());
  }

  @Test
  @Description("GetById - mainCategory with projections")
  @TmsLink("28501079")
  public void C28501079_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    List<String> listProjections = List.of("name", "activeRegion");
    MainCategory grpcResponse =
        mainCategoriesClient.getById(mainCategories.getId(), listProjections).getDocument();

    Assert.assertNotNull(grpcResponse.getId());
    Assert.assertEquals(grpcResponse.getName(), mainCategories.getName());
    Assert.assertEquals(grpcResponse.getActiveRegion(), mainCategories.getActiveRegion());
    Assert.assertTrue(grpcResponse.getSlug().isEmpty());
    Assert.assertTrue(grpcResponse.getUpdatedAt().isEmpty());
    Assert.assertTrue(grpcResponse.getCreatedAt().isEmpty());
    Assert.assertEquals(grpcResponse.getOrder(), 0);
    Assert.assertFalse(grpcResponse.getPlutoOfficeOnly());
    Assert.assertFalse(grpcResponse.getHideMainCategory());
  }

  @Test
  @Description("GetById - mainCategory with invalid projections")
  @TmsLink("28501080")
  public void C28501080_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();

    MainCategory grpcResponse =
        mainCategoriesClient.getById(mainCategories.getId(), List.of("invalid")).getDocument();

    Assert.assertNotNull(grpcResponse.getId());
    Assert.assertTrue(grpcResponse.getName().isEmpty());
    Assert.assertTrue(grpcResponse.getActiveRegion().isEmpty());
    Assert.assertTrue(grpcResponse.getSlug().isEmpty());
    Assert.assertTrue(grpcResponse.getUpdatedAt().isEmpty());
    Assert.assertTrue(grpcResponse.getCreatedAt().isEmpty());
    Assert.assertEquals(grpcResponse.getOrder(), 0);
    Assert.assertFalse(grpcResponse.getPlutoOfficeOnly());
    Assert.assertFalse(grpcResponse.getHideMainCategory());
  }

  @Test
  @Description("GetById - mainCategory with all projections")
  @TmsLink("28501081")
  public void C28501081_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    List<String> listProjections =
        List.of(
            "name",
            "activeRegion",
            "slug",
            "distribution",
            "plutoOfficeOnly",
            "hideMainCategory",
            "PNGimage",
            "SVGImage");
    MainCategory grpcResponse =
        mainCategoriesClient.getById(mainCategories.getId(), listProjections).getDocument();

    MainCategories grpcMainCategories =
        mainCategoriesUtils.mapGrpcObjectToPojo(grpcResponse, MainCategories.class);

    Assert.assertNotNull(grpcMainCategories.getId());
    Assert.assertEquals(grpcMainCategories.getName(), mainCategories.getName());
    Assert.assertEquals(grpcMainCategories.getActiveRegion(), mainCategories.getActiveRegion());
    Assert.assertEquals(grpcMainCategories.getSlug(), mainCategories.getSlug());
    Assert.assertEquals(grpcMainCategories.getDistribution(), mainCategories.getDistribution());
    Assert.assertEquals(
        grpcMainCategories.getPlutoOfficeOnly(), mainCategories.getPlutoOfficeOnly());
    Assert.assertEquals(
        grpcMainCategories.getHideMainCategory(), mainCategories.getHideMainCategory());
    Assert.assertTrue(grpcResponse.getCreatedAt().isEmpty());
    Assert.assertTrue(grpcResponse.getUpdatedAt().isEmpty());
  }

  @Test
  @Description("UpdateFields - update test fields")
  @TmsLink("28501071")
  public void C28501071_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName() + ".")
            .setPlutoOfficeOnly(!doc.getPlutoOfficeOnly())
            .setDistribution(doc.getDistribution())
            .build();

    List<String> listUpdateFields = List.of("name", "plutoOfficeOnly", "distribution");

    MainCategory response =
        mainCategoriesClientAuth
            .updateFields(mainCategories.getId(), mainRequest, listUpdateFields)
            .getDocument();

    Assert.assertEquals(response.getId(), doc.getId());
    Assert.assertEquals(response.getName(), doc.getName() + ".");
    Assert.assertEquals(!response.getPlutoOfficeOnly(), doc.getPlutoOfficeOnly());
    Assert.assertEquals(response.getDistribution(), doc.getDistribution());

    MainCategory mainRequestRevert =
        MainCategory.newBuilder()
            .setName(doc.getName())
            .setPlutoOfficeOnly(doc.getPlutoOfficeOnly())
            .setDistribution(doc.getDistribution())
            .build();

    MainCategory responseRevert =
        mainCategoriesClientAuth
            .updateFields(mainCategories.getId(), mainRequestRevert, listUpdateFields)
            .getDocument();

    Assert.assertEquals(responseRevert.getName(), doc.getName());
  }

  @Test
  @Description("DeleteById - happy path")
  @TmsLink("28501072")
  public void C28501072_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName())
            .setSlug(doc.getSlug())
            .setActiveRegion(doc.getActiveRegion())
            .build();

    MainCategory createdResponse =
        mainCategoriesClientAuth.createRequest(mainRequest).getDocument();
    Assert.assertFalse(createdResponse.getId().isEmpty());

    tv.pluto.ip.dal.maincategories.MainCategories.DeleteByIdResponse deleteResponse =
        mainCategoriesClientAuth.deleteById(createdResponse.getId());

    Assert.assertEquals(deleteResponse.getDeletedCount(), 1);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "UNAUTHENTICATED: DB writes not allowed without authentication")
  @Description("DeleteById - no token")
  @TmsLink("28501073")
  public void C28501073_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName())
            .setSlug(doc.getSlug())
            .setActiveRegion(doc.getActiveRegion())
            .build();

    mainCategoriesClient.createRequest(mainRequest).getDocument();
  }

  @Test
  @Description("DeleteById - delete id twice")
  @TmsLink("28501074")
  public void C28501074_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName())
            .setSlug(doc.getSlug())
            .setActiveRegion(doc.getActiveRegion())
            .build();

    MainCategory createdResponse =
        mainCategoriesClientAuth.createRequest(mainRequest).getDocument();
    Assert.assertFalse(createdResponse.getId().isEmpty());

    tv.pluto.ip.dal.maincategories.MainCategories.DeleteByIdResponse deleteResponse =
        mainCategoriesClientAuth.deleteById(createdResponse.getId());

    Assert.assertEquals(deleteResponse.getDeletedCount(), 1);

    try {
      mainCategoriesClientAuth.deleteById(createdResponse.getId());
      Assert.fail("No errors in the response");
    } catch (RuntimeException e) {
      Assert.assertEquals(e.getMessage(), NOT_FOUND_IDS_CATEGORIES);
    }
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_IDS_CATEGORIES)
  @Description("DeleteById - invalid mainCategory id with a token")
  @TmsLink("28501075")
  public void C28501075_TEST() {
    mainCategoriesClientAuth.deleteById("00000fbff9135b0008300000");
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_IDS_CATEGORIES)
  @Description("DeleteById - invalid mainCategory id without a token")
  @TmsLink("28501076")
  public void C28501076_TEST() {
    mainCategoriesClient.deleteById("00000fbff9135b0008300000");
  }

  @Test
  @Description("GetChannelsList - verify all channels have the same category")
  @TmsLink("28501082")
  public void C28501082_TEST() {
    Channels channels = channelsUtils.getExistsAndSizeNotZero("categories", 5);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C24576324. CategoryId: " + mainCategoryId);

    MainCategories mainCategories = mainCategoriesUtils.getDocumentById(mainCategoryId);
    Assert.assertNotNull(mainCategories);
    Assert.assertNotNull(mainCategories.getStackingOrder());

    List<Channels> listChannels =
        channelsUtils.getDocumentsByFieldAndId(CATEGORY_ID, mainCategoryId);

    boolean doesCategoryExist =
        listChannels.stream()
            .allMatch(
                channel ->
                    channel.getCategories().stream()
                        .anyMatch(category -> category.getCatId().equals(mainCategoryId)));

    Assert.assertTrue(doesCategoryExist);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelList =
        mainCategoriesClient.getChannelList(mainCategoryId, null, null, null, null, null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelList.getDocumentsList();

    if (mainCategories.getStackingOrder().equalsIgnoreCase("natural")) {
      List<Integer> listNumbersGrpc =
          grpcListChannels.stream().map(c -> c.getNumber()).collect(Collectors.toList());
      List<Integer> listNumbersSorted = new ArrayList<>(listNumbersGrpc);
      Collections.sort(listNumbersSorted);

      Assert.assertEquals(listNumbersGrpc.size(), listNumbersSorted.size());
    } else {
      LogUtils.logInfoMessage("Stacking order: " + mainCategories.getStackingOrder());
      List<String> listCatIds =
          grpcListChannels.stream()
              .map(c -> c.getCategories(0).getCatId())
              .collect(Collectors.toList());
      List<MainCategories> listMainCategories = mainCategoriesUtils.getDocumentsByIds(listCatIds);
      Collections.sort(listMainCategories, Comparator.comparingInt(MainCategories::getOrder));
      List<String> listSortedCatIds =
          listMainCategories.stream().map(m -> m.getId().toString()).collect(Collectors.toList());

      Assert.assertEquals(listSortedCatIds, listCatIds);
    }
  }

  @Test
  @Description("GetChannelsList - natural order test")
  @TmsLink("28501084")
  public void C28501084_TEST() {
    String sortOrder = "natural";
    Channels channels = channelsUtils.getExistsAndSizeNotZero("categories", 6);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C33739602. CategoryId: " + mainCategoryId);

    MainCategories mainCategories = mainCategoriesUtils.getDocumentById(mainCategoryId);
    Assert.assertNotNull(mainCategories);
    Assert.assertNotNull(mainCategories.getStackingOrder());

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse grpcResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, null, null, null, null, sortOrder, null);

    Assert.assertEquals(grpcResponse.getOrder(), sortOrder);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        grpcResponse.getDocumentsList();

    List<Integer> list1 = grpcListChannels.stream().map(c -> c.getNumber()).toList();
    List<Integer> sortedList = new ArrayList<>(list1);
    Collections.sort(sortedList);

    Assert.assertEquals(list1, sortedList);

    List<Channels> listChannels =
        channelsUtils.getDocumentsByFieldAndId(CATEGORY_ID, mainCategoryId);

    List<Channels> grpcConvertedListChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);
    grpcConvertedListChannels.sort(Comparator.comparing(Channels::getId));
    listChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(grpcConvertedListChannels, listChannels);
  }

  @Test
  @Description("GetChannelsList - custom order order")
  @TmsLink("28501085")
  public void C28501085_TEST() {
    String sortOrder = "custom";
    Channels channels = channelsUtils.getExistsAndSizeNotZero("categories", 7);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C33739603. CategoryId: " + mainCategoryId);

    MainCategories mainCategories = mainCategoriesUtils.getDocumentById(mainCategoryId);
    Assert.assertNotNull(mainCategories);
    Assert.assertNotNull(mainCategories.getStackingOrder());

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse grpcResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, null, null, null, null, sortOrder, null);

    List<Channels> listChannels =
        channelsUtils.getDocumentsByFieldAndId(CATEGORY_ID, mainCategoryId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> documentsList =
        grpcResponse.getDocumentsList();

    List<Integer> listOrder =
        documentsList.stream()
            .flatMap(c -> c.getCategoriesList().stream())
            .filter(cat -> cat.getCatId().equals(mainCategoryId))
            .map(tv.pluto.ip.dal.maincategories.MainCategories.Category::getOrder)
            .toList();

    List<Integer> sortedList = new ArrayList<>(listOrder);
    Collections.sort(sortedList);

    Assert.assertEquals(listOrder, sortedList);

    List<Channels> grpcConvertedListChannels =
        channelsUtils.mapGrpcObjectsToPojo(documentsList, Channels.class);

    grpcConvertedListChannels.sort(Comparator.comparing(Channels::getId));
    listChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(grpcConvertedListChannels, listChannels);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetChannelsList - custom order order with a limit")
  @TmsLink("28501086")
  public void C28501086_TEST(Integer sortValue) {
    int limit = 10;
    Channels channels = channelsUtils.getExistsAndSizeNotZero("categories", 7);
    Boolean plutoOfficeOnly = channels.getPlutoOfficeOnly();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C28501086. CategoryId: " + mainCategoryId);

    MainCategories mainCategories = mainCategoriesUtils.getDocumentById(mainCategoryId);
    Assert.assertNotNull(mainCategories);
    Assert.assertNotNull(mainCategories.getStackingOrder());

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort allPagedSort =
        mainCategoriesClient.getAllPagedSort("_id", sortValue);

    Boolean isPlutoOfficeOnly = channels.getPlutoOfficeOnly();

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            "plutoOfficeOnly", isPlutoOfficeOnly.toString(), "boolean", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse grpcResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, limit, null, List.of(allPagedSort), List.of(filter), null, null);

    List<Channels> listAllChannelsDb =
        channelsUtils.getDocumentsByFieldAndId(CATEGORY_ID, mainCategoryId);

    List<Channels> mutableListChannels =
        listAllChannelsDb.stream()
            .filter(c -> c.getPlutoOfficeOnly().equals(plutoOfficeOnly))
            .toList();

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> documentsList =
        grpcResponse.getDocumentsList();

    boolean allMatch =
        documentsList.stream().allMatch(e -> e.getPlutoOfficeOnly() == plutoOfficeOnly);

    Assert.assertTrue(allMatch);
    Assert.assertTrue(documentsList.size() <= limit);

    List<Channels> grpcConvertedListChannels =
        channelsUtils.mapGrpcObjectsToPojo(documentsList, Channels.class);

    List<Channels> listChannels = new ArrayList<>(mutableListChannels);

    if (sortValue == 1) listChannels.sort(Comparator.comparing(Channels::getId));
    else listChannels.sort(Comparator.comparing(Channels::getId).reversed());

    Assert.assertTrue(listChannels.containsAll(grpcConvertedListChannels));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_CATEGORIES)
  @Description("GetChannelsList - not valid category")
  @TmsLink("28501087")
  public void C28501087_TEST() {
    mainCategoriesClient.getChannelList(
        "61d62705dd13950007132000", null, null, null, null, null, null);
  }

  @Test
  @Description("GetVodCategoriesList - verify all Vod categories have the same category")
  @TmsLink("28501088")
  public void C28501088_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getExistsAndSizeNotZero("categories");
    String catId = vodCategories.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("MainCategoryId: " + catId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
        mainCategoriesClient
            .getVodCategoriesList(catId, null, null, null, null, null, null)
            .getDocumentsList();

    List<VodCategories> listVodCategories =
        vodCategoryUtils.getDocumentsByFieldAndId(CATEGORY_ID, catId);

    boolean doesCategoryExist =
        listVodCategories.stream()
            .allMatch(
                vodCategory ->
                    vodCategory.getCategories().stream()
                        .anyMatch(cat -> cat.getCatId().equals(catId)));

    boolean doesCategoryExistGrpc =
        vodDocsList.stream()
            .allMatch(
                vodCategory ->
                    vodCategory.getCategoriesList().stream()
                        .anyMatch(cat -> cat.getCatId().equals(catId)));

    Assert.assertTrue(doesCategoryExist);
    Assert.assertTrue(doesCategoryExistGrpc);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_CATEGORIES)
  @Description("GetVodCategoriesList - not valid categories")
  @TmsLink("28501094")
  public void C28501094_TEST() {
    mainCategoriesClient.getVodCategoriesList(
        "61d62705dd13950007132000", null, null, null, null, null, null);
  }

  @Test(dataProvider = "custom-null")
  @Description("SetOrderInChannelList - set custom order for channels")
  @TmsLink("28501095")
  public void C28501095_TEST(String order) {
    Channels chan = channelsUtils.getExistsAndSizeNotZero("categories", 14);
    String mainCatId = chan.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C28501095. Test mainCatId: " + mainCatId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> channelListResponse =
        mainCategoriesClient
            .getChannelList(mainCatId, null, null, null, null, null, null)
            .getDocumentsList();

    List<String> listIdsResponse =
        channelListResponse.stream()
            .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getId)
            .collect(Collectors.toList());

    List<tv.pluto.ip.dal.maincategories.MainCategories.ChannelOrderResponse>
        listChannelsWithMainCat =
            mainCategoriesClient
                .setOrderInChannelsList(listIdsResponse, mainCatId, order)
                .getDocumentsList();

    List<Channels> listChannelsUnsorted = channelsUtils.getDocumentsByIds(listIdsResponse);

    Map<String, Channels> channelsById =
        listChannelsUnsorted.stream()
            .collect(Collectors.toMap(Channels::getId, channel -> channel));

    listChannelsUnsorted = listIdsResponse.stream().map(channelsById::get).toList();
    List<Channels> listChannels = new ArrayList<>(listChannelsUnsorted);

    List<Integer> listCatOrder = new ArrayList<>();

    for (Channels channel : listChannels) {
      Category category =
          channel.getCategories().stream()
              .filter(c -> c.getCatId().equals(mainCatId))
              .findFirst()
              .orElseThrow();

      listCatOrder.add(category.getOrder());
    }

    Assert.assertFalse(listCatOrder.isEmpty());

    List<Integer> listCatOrderSorted = new ArrayList<>(listCatOrder);
    listCatOrderSorted.sort(Comparator.naturalOrder());

    // verify logic for custom order in channels
    Assert.assertEquals(listCatOrderSorted, listCatOrder);

    listChannels.sort(Comparator.comparing(Channels::getId));

    List<Channels> grpcListChannels =
        channelsUtils.mapGrpcObjectsToPojo(listChannelsWithMainCat, Channels.class);

    grpcListChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listChannels, grpcListChannels, "The list of channels do not match");
  }

  @Test
  @Description("SetOrderInChannelList - set natural order for channels")
  @TmsLink("28501096")
  public void C28501096_TEST() {
    String order = "natural";
    Channels chan = channelsUtils.getExistsAndSizeNotZero("categories", 15);
    String mainCatId = chan.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C34087778. Test mainCatId: " + mainCatId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> channelListResponse =
        mainCategoriesClient
            .getChannelList(mainCatId, null, null, null, null, null, null)
            .getDocumentsList();

    List<String> listIdsResponse =
        channelListResponse.stream()
            .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getId)
            .collect(Collectors.toList());

    List<tv.pluto.ip.dal.maincategories.MainCategories.ChannelOrderResponse>
        listChannelsWithMainCat =
            mainCategoriesClient
                .setOrderInChannelsList(listIdsResponse, mainCatId, order)
                .getDocumentsList();

    List<Channels> listChannelsUnsorted = channelsUtils.getDocumentsByIds(listIdsResponse);

    Map<String, Channels> channelsById =
        listChannelsUnsorted.stream()
            .collect(Collectors.toMap(Channels::getId, channel -> channel));

    listChannelsUnsorted = listIdsResponse.stream().map(channelsById::get).toList();
    List<Channels> listChannels = new ArrayList<>(listChannelsUnsorted);

    Assert.assertFalse(listChannels.isEmpty(), "No channels found");

    Map<Integer, Integer> mapChannelOrderMainCatNumber = new HashMap<>();

    for (Channels channel : listChannels) {
      int channelNumber = channel.getNumber();

      // bad data
      if (channelNumber == 0) continue;

      Category category =
          channel.getCategories().stream()
              .filter(c -> c.getCatId().equals(mainCatId))
              .findFirst()
              .orElseThrow();

      mapChannelOrderMainCatNumber.put(channelNumber, category.getOrder());
    }

    Map<Integer, Integer> sortedMap = new TreeMap<>(mapChannelOrderMainCatNumber);
    List<Integer> mainCatValuesResponse = new ArrayList<>(sortedMap.values());
    List<Integer> sortedValues = new ArrayList<>(mainCatValuesResponse);
    Collections.sort(sortedValues);

    Assert.assertEquals(mainCatValuesResponse, sortedValues, "Main category values do not match");

    listChannels.sort(Comparator.comparing(Channels::getId));

    List<Channels> grpcListChannels =
        channelsUtils.mapGrpcObjectsToPojo(listChannelsWithMainCat, Channels.class);

    grpcListChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listChannels, grpcListChannels, "The list of channels do not match");
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: '' is not a valid Channel ID")
  @Description("SetOrderInChannelList - is not a valid Channel Id")
  @TmsLink("28501103")
  public void C28501103_TEST() {
    // To do to find a logic to get mainCatId in db to trigger this error
    mainCategoriesClient.setOrderInChannelsList(List.of(""), "644bb672d3fdde000801cd75", null);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("SetOrderInChannelList - set order for invalid channel")
  @TmsLink("28501097")
  public void C28501097_TEST() {
    Channels chan = channelsUtils.getExistsAndSizeNotZero("categories", 12);
    String mainCatId = chan.getCategories().get(0).getCatId();
    mainCategoriesClient.setOrderInChannelsList(
        List.of("5245c8fc1beac6ec4a000000"), mainCatId, null);
  }

  @Test
  @Description("SetOrderInVodList - set order for vod categories")
  @TmsLink("28501098")
  public void C28501098_TEST() {
    VodCategories vodCategory = vodCategoryUtils.getExistsAndSizeNotZero("categories", 4);
    String mainCatId = vodCategory.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("Test mainCatId: " + mainCatId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> documentsList =
        mainCategoriesClient
            .getVodCategoriesList(mainCatId, null, null, null, null, null, null)
            .getDocumentsList();
    List<String> listIds = documentsList.stream().map(c -> c.getId()).collect(Collectors.toList());
    Collections.shuffle(listIds);

    tv.pluto.ip.dal.maincategories.MainCategories.SetOrderInVodListResponse
        setOrderInVodListResponse = mainCategoriesClient.setOrderInVodList(listIds, mainCatId);

    List<String> sortedChannelIdsByOrder =
        setOrderInVodListResponse.getDocumentsList().stream()
            .sorted(
                Comparator.comparingInt(
                    e ->
                        e.getCategoriesList().stream()
                            .filter(v -> v.getCatId().equals(mainCatId))
                            .findFirst()
                            .get()
                            .getOrder()))
            .map(e -> e.getId())
            .collect(Collectors.toList());

    Assert.assertEquals(listIds, sortedChannelIdsByOrder);
  }

  @Test
  @Description("GetVodCategoriesList - set custom order for vod categories")
  @TmsLink("28501092")
  public void C28501092_TEST() {
    VodCategories vodCategory = vodCategoryUtils.getExistsAndSizeNotZero("categories", 6);
    String mainCatId = vodCategory.getCategories().get(0).getCatId();
    LogUtils.logInfoMessage("C33739551. Test mainCatId: " + mainCatId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> documentsList =
        mainCategoriesClient
            .getVodCategoriesList(mainCatId, "custom", null, null, null, null, null)
            .getDocumentsList();

    List<VodCategories> listVodCategory =
        vodCategoryUtils.getDocumentsByFieldAndId(CATEGORY_ID, mainCatId);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Category> listGrpcMainCategories =
        documentsList.stream()
            .flatMap(cat -> cat.getCategoriesList().stream())
            .filter(cat -> cat.getCatId().equals(mainCatId))
            .distinct()
            .toList();

    List<Categories> listDbCategories =
        listVodCategory.stream()
            .flatMap(cat -> cat.getCategories().stream())
            .filter(cat -> cat.getCatId().equals(mainCatId))
            .sorted(Comparator.comparing(Categories::getOrder))
            .distinct()
            .toList();

    List<Categories> listGrpcCats =
        mainCategoriesUtils.mapGrpcObjectsToPojo(listGrpcMainCategories, Categories.class);

    Assert.assertFalse(listGrpcCats.isEmpty());
    List<Integer> listOrders = listGrpcCats.stream().map(Categories::getOrder).toList();
    List<Integer> sortedNumbers = new ArrayList<>(listOrders);
    Collections.sort(sortedNumbers);

    Assert.assertEquals(listOrders, sortedNumbers, "Orders should be sorted in ascending order");
    Assert.assertEquals(listGrpcCats, listDbCategories);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INTERNAL: MainCategory not found")
  @Description("SetOrderInVodList - set order for invalid id")
  @TmsLink("28501099")
  public void C28501099_TEST() {
    String mainCatId = "6049d299b704d80007800000";
    mainCategoriesClient.setOrderInVodList(List.of(mainCatId), mainCatId);
  }

  @Test(dataProvider = "is-true-false")
  @Description("GetById/Create - hideMainCategory")
  @TmsLink("28501100")
  public void C28501100_TEST(boolean isTrue) {
    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName("testName")
            .setSlug("testslug")
            .setActiveRegion("us")
            .setHideMainCategory(isTrue)
            .build();

    MainCategory createMainGrpc = mainCategoriesClientAuth.createRequest(mainRequest).getDocument();

    Assert.assertNotNull(createMainGrpc.getId());

    MainCategory byIdMainGrpc =
        mainCategoriesClient.getById(createMainGrpc.getId(), null).getDocument();
    Assert.assertEquals(mainRequest.getHideMainCategory(), byIdMainGrpc.getHideMainCategory());
    Assert.assertEquals(createMainGrpc.getName(), byIdMainGrpc.getName());
    Assert.assertTrue(byIdMainGrpc.getSlug().contains(mainRequest.getSlug()));
    Assert.assertEquals(mainRequest.getActiveRegion(), byIdMainGrpc.getActiveRegion());

    Assert.assertEquals(
        mainCategoriesClientAuth.deleteById(createMainGrpc.getId()).getDeletedCount(), 1);
  }

  @Test(dataProvider = "is-true-false")
  @Description("GetByIds - hideMainCategory")
  @TmsLink("28501101")
  public void C28501101_TEST(boolean isTrue) {
    MainCategories categories = mainCategoriesUtils.getRandomDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(categories.getName())
            .setSlug(categories.getSlug())
            .setActiveRegion(categories.getActiveRegion())
            .setHideMainCategory(isTrue)
            .build();

    MainCategory createMainGrpc = mainCategoriesClientAuth.createRequest(mainRequest).getDocument();

    MainCategory byIdMainGrpc =
        mainCategoriesClient.getByIds(List.of(createMainGrpc.getId())).getDocuments(0);
    Assert.assertEquals(createMainGrpc.getHideMainCategory(), byIdMainGrpc.getHideMainCategory());
    Assert.assertEquals(createMainGrpc.getName(), byIdMainGrpc.getName());
    Assert.assertTrue(createMainGrpc.getSlug().contains(byIdMainGrpc.getSlug()));
    Assert.assertEquals(createMainGrpc.getActiveRegion(), byIdMainGrpc.getActiveRegion());

    Assert.assertEquals(
        mainCategoriesClientAuth.deleteById(createMainGrpc.getId()).getDeletedCount(), 1);
  }

  @Test(dataProvider = "is-true-false")
  @TmsLink("28501102")
  @Description("UpdateFields - hideMainCategory")
  public void C28501102_TEST(boolean isTrue) {
    MainCategories doc = mainCategoriesUtils.getRandomDocument();

    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName(doc.getName() + ".")
            .setPlutoOfficeOnly(!doc.getPlutoOfficeOnly())
            .setHideMainCategory(isTrue)
            .build();

    List<String> listUpdateFields = List.of("name", "plutoOfficeOnly", "hideMainCategory");

    MainCategory response =
        mainCategoriesClientAuth
            .updateFields(doc.getId(), mainRequest, listUpdateFields)
            .getDocument();

    MainCategory byIdMainGrpc = mainCategoriesClient.getById(doc.getId(), null).getDocument();
    Assert.assertEquals(response.getHideMainCategory(), isTrue);
    Assert.assertEquals(response.getName(), byIdMainGrpc.getName());
    Assert.assertEquals(mainRequest.getName(), byIdMainGrpc.getName());
    Assert.assertTrue(response.getSlug().contains(byIdMainGrpc.getSlug()));
  }

  @Test
  @Description("GetAllPaged - limit")
  @TmsLink("28501104")
  public void C28501104_TEST() {
    int limit = 10;
    ManagedChannel channel = grpcChannelManager.getChannel();

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false).getAllPaged(limit, 0, null, null, true, null);

    List<MainCategories> listMainCategoriesGrpc =
        mainCategoriesUtils.mapGrpcObjectsToPojo(
            getAllPaged.getDocumentsList(), MainCategories.class);

    List<String> listIds =
        listMainCategoriesGrpc.stream().map(MainCategories::getId).collect(Collectors.toList());
    List<MainCategories> listMainCategoriesMongoDb = mainCategoriesUtils.getDocumentsByIds(listIds);

    listMainCategoriesGrpc.sort(Comparator.comparing(MainCategories::getId));
    listMainCategoriesMongoDb.sort(Comparator.comparing(MainCategories::getId));

    Assert.assertFalse(listMainCategoriesGrpc.isEmpty());
    Assert.assertEquals(listMainCategoriesGrpc, listMainCategoriesMongoDb);
    Assert.assertEquals(getAllPaged.getMetadata().getTotalItems(), limit);
  }

  @Test
  @Description("GetAllPaged - filter by id and projection")
  @TmsLink("28501105")
  public void C28501105_TEST() {
    int limit = 1;
    ManagedChannel channel = grpcChannelManager.getChannel();
    MainCategories randomDocument = mainCategoriesUtils.getRandomDocument();
    String mainId = randomDocument.getId();

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter("_id", mainId, "string", null);
    List<tv.pluto.ip.dal.maincategories.MainCategories.Filter> listFilters = List.of(filter);
    List<String> listProjections = List.of("order", "name");

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(limit, 0, null, listFilters, true, listProjections);

    Assert.assertEquals(getAllPaged.getDocumentsList().size(), 1);
    MainCategory mainCategoryGrpc = getAllPaged.getDocumentsList().get(0);

    Assert.assertEquals(mainCategoryGrpc.getId(), mainId);
    Assert.assertEquals(mainCategoryGrpc.getName(), randomDocument.getName());
    Assert.assertEquals(mainCategoryGrpc.getOrder(), randomDocument.getOrder());
    Assert.assertNotEquals(mainCategoryGrpc.getActiveRegion(), randomDocument.getActiveRegion());
    Assert.assertTrue(mainCategoryGrpc.getActiveRegion().isEmpty());
    Assert.assertTrue(mainCategoryGrpc.getCreatedAt().isEmpty());
    Assert.assertEquals(getAllPaged.getMetadata().getTotalItems(), limit);
    Assert.assertEquals(getAllPaged.getMetadata().getCurrentOffset(), 0);
  }

  @Test
  @Description("GetAllPaged - filter name")
  @TmsLink("28501106")
  public void C28501106_TEST() {
    ManagedChannel channel = grpcChannelManager.getChannel();
    MainCategories randomDocument = mainCategoriesUtils.getExistsAndSizeNotZero("name");

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter("name", randomDocument.getName(), "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Filter> listFilters = List.of(filter);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, null, listFilters, true, null);

    Assert.assertFalse(getAllPaged.getDocumentsList().isEmpty());
    getAllPaged
        .getDocumentsList()
        .forEach(
            mainCategoryGrpc ->
                Assert.assertEquals(mainCategoryGrpc.getName(), randomDocument.getName()));
  }

  @Test
  @Description("GetAllPaged - filter activeRegion")
  @TmsLink("28501107")
  public void C28501107_TEST() {
    ManagedChannel channel = grpcChannelManager.getChannel();
    MainCategories randomDocument = mainCategoriesUtils.getExistsAndSizeNotZero("activeRegion");

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            "activeRegion", randomDocument.getActiveRegion(), "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Filter> listFilters = List.of(filter);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, null, listFilters, true, null);

    Assert.assertFalse(getAllPaged.getDocumentsList().isEmpty());
    getAllPaged
        .getDocumentsList()
        .forEach(
            mainCategoryGrpc ->
                Assert.assertEquals(
                    mainCategoryGrpc.getActiveRegion(), randomDocument.getActiveRegion()));
  }

  @Test
  @Description("GetAllPaged - filter plutoOfficeOnly")
  @TmsLink("28501108")
  public void C28501108_TEST() {
    ManagedChannel channel = grpcChannelManager.getChannel();
    MainCategories randomDocument = mainCategoriesUtils.getExistsAndSizeNotZero("plutoOfficeOnly");

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            "plutoOfficeOnly", randomDocument.getPlutoOfficeOnly().toString(), "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Filter> listFilters = List.of(filter);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, null, listFilters, true, null);

    Assert.assertFalse(getAllPaged.getDocumentsList().isEmpty());
    getAllPaged
        .getDocumentsList()
        .forEach(
            mainCategoryGrpc ->
                Assert.assertEquals(
                    mainCategoryGrpc.getPlutoOfficeOnly(), randomDocument.getPlutoOfficeOnly()));
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by name")
  @TmsLink("28501109")
  public void C28501109_TEST(int sortValue) {
    String sortName = "name";
    ManagedChannel channel = grpcChannelManager.getChannel();

    Collation collation = Collation.builder().locale("en_US").numericOrdering(true).build();
    Bson bSort;

    if (sortValue == 1) bSort = orderBy(ascending(sortName));
    else bSort = orderBy(descending(sortName));

    DocumentQuery documentQuery =
        DocumentQuery.builder()
            .limit(MAX_LIMIT)
            .offset(0)
            .sort(bSort)
            .collation(collation)
            .projections(null)
            .build();

    List<MainCategories> mongoMainCategoriesList =
        mainCategoriesUtils.getDocumentsWithCollation(documentQuery);

    List<String> listProjections = List.of("order", sortName);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort sort =
        tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort.newBuilder()
            .setField(sortName)
            .setValue(sortValue)
            .build();

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, List.of(sort), null, true, listProjections);

    List<MainCategories> listMainCategoriesGrpc =
        mainCategoriesUtils.mapGrpcObjectsToPojo(
            getAllPaged.getDocumentsList(), MainCategories.class);

    Assert.assertFalse(mongoMainCategoriesList.isEmpty());

    Assert.assertFalse(listMainCategoriesGrpc.isEmpty());
    List<String> grpcNames =
        listMainCategoriesGrpc.stream().map(MainCategories::getName).collect(Collectors.toList());
    List<String> mongoNames =
        mongoMainCategoriesList.stream().map(MainCategories::getName).collect(Collectors.toList());
    Assert.assertEquals(grpcNames, mongoNames);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by activeRegion")
  @TmsLink("28501110")
  public void C28501110_TEST(int sortValue) {
    String sortName = "activeRegion";
    ManagedChannel channel = grpcChannelManager.getChannel();

    Collation collation = Collation.builder().locale("en_US").numericOrdering(true).build();
    Bson bSort = (sortValue == 1) ? orderBy(ascending(sortName)) : orderBy(descending(sortName));

    DocumentQuery documentQuery =
        DocumentQuery.builder()
            .limit(MAX_LIMIT)
            .offset(0)
            .sort(bSort)
            .collation(collation)
            .projections(null)
            .build();

    List<MainCategories> mongoMainCategoriesList =
        mainCategoriesUtils.getDocumentsWithCollation(documentQuery);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort sort =
        tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort.newBuilder()
            .setField(sortName)
            .setValue(sortValue)
            .build();

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, List.of(sort), null, true, null);

    List<MainCategories> listMainCategoriesGrpc =
        mainCategoriesUtils.mapGrpcObjectsToPojo(
            getAllPaged.getDocumentsList(), MainCategories.class);

    Assert.assertFalse(listMainCategoriesGrpc.isEmpty());

    List<String> grpcActiveRegionGrpc =
        listMainCategoriesGrpc.stream()
            .map(MainCategories::getActiveRegion)
            .collect(Collectors.toList());

    List<String> grpcActiveRegionDb =
        mongoMainCategoriesList.stream()
            .map(MainCategories::getActiveRegion)
            .collect(Collectors.toList());

    Assert.assertEquals(grpcActiveRegionGrpc, grpcActiveRegionDb);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by hideMainCategory")
  @TmsLink("28501111")
  public void C28501111_TEST(int sortValue) {
    String sortName = "hideMainCategory";
    ManagedChannel channel = grpcChannelManager.getChannel();

    Collation collation = Collation.builder().locale("en_US").numericOrdering(true).build();
    Bson bSort = (sortValue == 1) ? orderBy(ascending(sortName)) : orderBy(descending(sortName));

    DocumentQuery documentQuery =
        DocumentQuery.builder()
            .limit(MAX_LIMIT)
            .offset(0)
            .sort(bSort)
            .collation(collation)
            .projections(null)
            .build();

    List<MainCategories> mongoMainCategoriesList =
        mainCategoriesUtils.getDocumentsWithCollation(documentQuery);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort sort =
        tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort.newBuilder()
            .setField(sortName)
            .setValue(sortValue)
            .build();

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, List.of(sort), null, true, null);

    List<MainCategories> listMainCategoriesGrpc =
        mainCategoriesUtils.mapGrpcObjectsToPojo(
            getAllPaged.getDocumentsList(), MainCategories.class);

    Assert.assertFalse(mongoMainCategoriesList.isEmpty());
    Assert.assertFalse(listMainCategoriesGrpc.isEmpty());

    List<Boolean> grpcMainCat =
        listMainCategoriesGrpc.stream()
            .map(MainCategories::getHideMainCategory)
            .collect(Collectors.toList());

    List<Boolean> dbMainCat =
        mongoMainCategoriesList.stream()
            .map(MainCategories::getHideMainCategory)
            .collect(Collectors.toList());

    Assert.assertEquals(grpcMainCat, dbMainCat);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by plutoOfficeOnly")
  @TmsLink("28501112")
  public void C28501112_TEST(int sortValue) {
    String sortName = "plutoOfficeOnly";
    ManagedChannel channel = grpcChannelManager.getChannel();

    Collation collation = Collation.builder().locale("en_US").numericOrdering(true).build();
    Bson bSort = (sortValue == 1) ? orderBy(ascending(sortName)) : orderBy(descending(sortName));

    DocumentQuery documentQuery =
        DocumentQuery.builder()
            .limit(MAX_LIMIT)
            .offset(0)
            .sort(bSort)
            .collation(collation)
            .projections(null)
            .build();

    List<MainCategories> mongoMainCategoriesList =
        mainCategoriesUtils.getDocumentsWithCollation(documentQuery);

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort sort =
        tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort.newBuilder()
            .setField(sortName)
            .setValue(sortValue)
            .build();

    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedResponse getAllPaged =
        new MainCategoriesClient(channel, false)
            .getAllPaged(MAX_LIMIT, 0, List.of(sort), null, true, null);

    List<MainCategories> listMainCategoriesGrpc =
        mainCategoriesUtils.mapGrpcObjectsToPojo(
            getAllPaged.getDocumentsList(), MainCategories.class);

    Assert.assertFalse(mongoMainCategoriesList.isEmpty());
    Assert.assertFalse(listMainCategoriesGrpc.isEmpty());

    List<Boolean> grpcPlutoOffice =
        listMainCategoriesGrpc.stream()
            .map(MainCategories::getPlutoOfficeOnly)
            .collect(Collectors.toList());

    List<Boolean> dbPlutoOffice =
        mongoMainCategoriesList.stream()
            .map(MainCategories::getPlutoOfficeOnly)
            .collect(Collectors.toList());

    Assert.assertEquals(grpcPlutoOffice, dbPlutoOffice);
  }

  @Test(
      dataProvider = "sort-values",
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INVALID_ARGUMENT.*")
  @TmsLink("28501113")
  @Description("GetAllPaged - sorting by invalid field")
  public void C28501113_TEST(int sortValue)
      throws NoSuchFieldException, IllegalAccessException, InvocationTargetException {
    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort sort =
        tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort.newBuilder()
            .setField("invalidField")
            .setValue(sortValue)
            .build();

    ManagedChannel channel = grpcChannelManager.getChannel();
    new MainCategoriesClient(channel, false)
        .getAllPagedException(MAX_LIMIT, 0, List.of(sort), null, true);
    System.out.println();
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetAllPaged - filter by invalid field")
  @TmsLink("28501114")
  public void C28501114_TEST()
      throws NoSuchFieldException, IllegalAccessException, InvocationTargetException {
    ManagedChannel channel = grpcChannelManager.getChannel();
    MainCategories randomDocument = mainCategoriesUtils.getExistsAndSizeNotZero("plutoOfficeOnly");

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            UUID.randomUUID().toString(),
            randomDocument.getPlutoOfficeOnly().toString(),
            "string",
            null);

    new MainCategoriesClient(channel, false)
        .getAllPagedException(MAX_LIMIT, 0, null, List.of(filter), true);
  }

  @Test
  @Description("BulkAssignVodsToMainCategoriesRequest - happy path")
  @TmsLink("28501115")
  public void C28501115_TEST() {
    Instant startTest = Instant.now().minusSeconds(60);
    String mainCat = ((MainCategories) mainCategoriesUtils.getRandomDocument()).getId();
    VodCategories vodCat = vodCategoryUtils.getRandomDocument();
    String vodCatId = vodCat.getId();

    tv.pluto.ip.dal.maincategories.MainCategories.BulkAssignVodsToMainCategoriesResponse
        bulkResponse =
            mainCategoriesClient.bulkAssignVodsToMainCategoriesRequest(mainCat, List.of(vodCatId));

    Assert.assertEquals(bulkResponse.getDocumentsCount(), 1);

    tv.pluto.ip.dal.maincategories.MainCategories.BulkVodsMainCategories bulkDoc =
        bulkResponse.getDocuments(0);
    Assert.assertEquals(bulkDoc.getVodId(), vodCatId);
    Assert.assertEquals(bulkDoc.getMainCategoryId(), mainCat);

    Instant createdVodResponse = Instant.parse(bulkDoc.getCreatedAt());
    Assert.assertEquals(createdVodResponse, vodCat.getCreatedAt().toInstant(ZoneOffset.UTC));

    Instant updatedVodResponse = Instant.parse(bulkDoc.getUpdatedAt());
    boolean dateBetweenDates =
        CommonUtils.isDateBetweenDates(
            startTest, Instant.now().plusSeconds(60), updatedVodResponse);
    Assert.assertTrue(dateBetweenDates);

    VodCategories vodCatAfterUpdate = vodCategoryUtils.getDocumentById(vodCatId);
    Categories categories =
        vodCatAfterUpdate.getCategories().stream()
            .filter(cat -> cat.getCatId().equals(mainCat))
            .findFirst()
            .orElseThrow(() -> new NoSuchElementException("Category not found for id: " + mainCat));

    Assert.assertEquals(categories.getCatId(), mainCat);
    Assert.assertFalse(categories.getId().isEmpty());
  }

  @Test
  @Description("BulkAssignVodsToMainCategoriesRequest - happy path list of vod ids")
  @TmsLink("28501116")
  public void C28501116_TEST() {
    int limit = 3;
    Instant startTest = Instant.now().minusSeconds(60);
    String mainCat = ((MainCategories) mainCategoriesUtils.getRandomDocument()).getId();
    List<VodCategories> listVodCat = vodCategoryUtils.getRandomDocuments(limit);
    List<String> listVodCatIds = listVodCat.stream().map(VodCategories::getId).toList();

    tv.pluto.ip.dal.maincategories.MainCategories.BulkAssignVodsToMainCategoriesResponse
        bulkResponse =
            mainCategoriesClient.bulkAssignVodsToMainCategoriesRequest(mainCat, listVodCatIds);

    Assert.assertEquals(bulkResponse.getDocumentsCount(), limit);

    List<tv.pluto.ip.dal.maincategories.MainCategories.BulkVodsMainCategories> documentsList =
        bulkResponse.getDocumentsList();

    documentsList.forEach(
        bulkDoc -> {
          VodCategories vodCat =
              listVodCat.stream()
                  .filter(v -> v.getId().equals(bulkDoc.getVodId()))
                  .findFirst()
                  .orElseThrow(
                      () -> new NoSuchElementException("Category not found for id: " + mainCat));

          Assert.assertEquals(bulkDoc.getMainCategoryId(), mainCat);

          Instant createdVodResponse = Instant.parse(bulkDoc.getCreatedAt());
          Assert.assertEquals(createdVodResponse, vodCat.getCreatedAt().toInstant(ZoneOffset.UTC));

          Instant updatedVodResponse = Instant.parse(bulkDoc.getUpdatedAt());
          boolean dateBetweenDates =
              CommonUtils.isDateBetweenDates(
                  startTest, Instant.now().plusSeconds(60), updatedVodResponse);
          Assert.assertTrue(dateBetweenDates);

          VodCategories vodCatAfterUpdate = vodCategoryUtils.getDocumentById(bulkDoc.getVodId());
          Categories categories =
              vodCatAfterUpdate.getCategories().stream()
                  .filter(cat -> cat.getCatId().equals(mainCat))
                  .findFirst()
                  .orElseThrow(
                      () -> new NoSuchElementException("Category not found for id: " + mainCat));

          Assert.assertEquals(categories.getCatId(), mainCat);
          Assert.assertFalse(categories.getId().isEmpty());
        });
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = INTERNAL_MESSAGE)
  @Description("BulkAssignVodsToMainCategoriesRequest - invalid ids")
  @TmsLink("28501117")
  public void C28501117_TEST() {
    String vodCatId = CommonUtils.generateRandomObjectId();
    mainCategoriesClient.bulkAssignVodsToMainCategoriesRequest(vodCatId, List.of(vodCatId));
  }

  @Test
  @Description("SetMainCategoriesOrder - set up order for main categories")
  @TmsLink("28501118")
  public void C28501118_TEST() {
    String activeRegion = "es";
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    MainCategory doc = mainCategoriesClient.getById(mainCategories.getId(), null).getDocument();

    int orderOne = doc.getOrder() + 1;
    int orderTwo = orderOne + 1;

    MainCategory mainRequest =
        mainCategoriesClient.getMainCategory("testDal1", orderOne, activeRegion);
    MainCategory mainRequest2 =
        mainCategoriesClient.getMainCategory("testDal2", orderTwo, activeRegion);

    MainCategory responseCreatedOne =
        mainCategoriesClientAuth.createRequest(mainRequest).getDocument();

    MainCategory responseCreatedTwo =
        mainCategoriesClientAuth.createRequest(mainRequest2).getDocument();

    String createdOneId = responseCreatedOne.getId();
    String createdTwoId = responseCreatedTwo.getId();

    tv.pluto.ip.dal.maincategories.MainCategories.MainCategoryOrder mainCatOneRequest =
        mainCategoriesClient.getMainCategoryOrder(createdOneId, orderOne);

    tv.pluto.ip.dal.maincategories.MainCategories.MainCategoryOrder mainCatTwoRequest =
        mainCatOneRequest.toBuilder().setId(createdTwoId).setOrder(orderTwo).build();

    List<tv.pluto.ip.dal.maincategories.MainCategories.MainCategoryOrder> documentsList =
        mainCategoriesClient
            .setMainCategoriesOrder(activeRegion, List.of(mainCatOneRequest, mainCatTwoRequest))
            .getDocumentsList();

    Assert.assertEquals(documentsList.size(), 2);

    List<String> createdIds = List.of(createdOneId, createdTwoId);

    createdIds.forEach(
        id ->
            documentsList.stream()
                .filter(m -> m.getId().equals(id))
                .findFirst()
                .ifPresentOrElse(
                    m -> {
                      if (m.getId().equals(createdOneId)) {
                        int dbOrder =
                            ((MainCategories) mainCategoriesUtils.getDocumentById(createdOneId))
                                .getOrder();

                        Assert.assertEquals(m.getOrder(), orderOne);
                        Assert.assertEquals(m.getOrder(), dbOrder);
                      } else if (m.getId().equals(createdTwoId)) {
                        Assert.assertEquals(m.getOrder(), orderTwo);
                        int dbOrder =
                            ((MainCategories) mainCategoriesUtils.getDocumentById(createdTwoId))
                                .getOrder();

                        Assert.assertEquals(m.getOrder(), dbOrder);
                      }
                    },
                    () -> Assert.fail("No order for id: " + id)));

    mainCategoriesClientAuth.deleteById(createdOneId);
    mainCategoriesClientAuth.deleteById(createdTwoId);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = INTERNAL_MESSAGE)
  @Description("SetMainCategoriesOrder - invalid activeRegion")
  @TmsLink("28501119")
  public void C28501119_TEST() {
    String id = ((MainCategories) mainCategoriesUtils.getRandomDocument()).getId();

    tv.pluto.ip.dal.maincategories.MainCategories.MainCategoryOrder mainCatOneRequest =
        mainCategoriesClient.getMainCategoryOrder(id, 1);

    mainCategoriesClient.setMainCategoriesOrder("invalid", List.of(mainCatOneRequest));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = INTERNAL_MESSAGE)
  @Description("SetMainCategoriesOrder - a different activeRegion")
  @TmsLink("28501120")
  public void C28501120_TEST() {
    MainCategories mainCategories = mainCategoriesUtils.getRandomDocument();
    String id = mainCategories.getId();
    String activeRegion =
        mainCategories.getActiveRegion().equalsIgnoreCase("us")
            ? "es"
            : mainCategories.getActiveRegion();

    tv.pluto.ip.dal.maincategories.MainCategories.MainCategoryOrder mainCatOneRequest =
        mainCategoriesClient.getMainCategoryOrder(id, 1);

    mainCategoriesClient.setMainCategoriesOrder(activeRegion, List.of(mainCatOneRequest));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_CATEGORIES)
  @Description("GetChannelsList - not valid category with order")
  @TmsLink("28501121")
  public void C28501121_TEST() {
    mainCategoriesClient.getChannelList(
        "58e1a299dca3c3a22fbd8319", null, null, null, null, "order", null);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("GetChannelsList - valid channelId not associated with category with order")
  @TmsLink("28501122")
  public void C28501122_Test() {
    mainCategoriesClient.getChannelList(
        "58e1a299dca3c3a22fbd8319a", null, null, null, null, "order", null);
  }

  @Test
  @Description("GetChannelsList - verify filters status")
  @TmsLink("28501123")
  public void C28501123_TEST() {
    String testField = "status";
    String testFieldValue = UUID.randomUUID().toString();
    Channels channels = channelsUtils.getChannelWithMainCategory(testField, 1, false);

    String testChannelId = channels.getId();
    String mainCategoryId = channels.getCategories().get(0).getCatId();

    LogUtils.logInfoMessage("C33689177. CategoryId: " + mainCategoryId);
    MainCategories mainCategories = mainCategoriesUtils.getDocumentById(mainCategoryId);
    Assert.assertNotNull(mainCategories);

    Document update = new Document(testField, testFieldValue);
    channelsUtils.updateDocument("_id", new ObjectId(testChannelId), update);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(testField, testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 10, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    // Unique testFieldValue id filter
    Assert.assertEquals(grpcListChannels.size(), 1);

    Channels grpcChannels =
        channelsUtils.mapGrpcObjectToPojo(grpcListChannels.get(0), Channels.class);
    Assert.assertEquals(grpcChannels, channels);
  }

  @Test
  @Description("GetChannelsList - verify filters regionFilter include")
  @TmsLink("28501124")
  public void C28501124_TEST() {
    String searchField = "regionFilter.include";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 2, true);

    String testFieldValue = channels.getRegionFilter().getInclude().get(0);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689179. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(searchField, testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify filters regionFilter exclude")
  @TmsLink("28501125")
  public void C28501125_TEST() {
    String searchField = "regionFilter.exclude";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 3, false);

    String testFieldValue = channels.getRegionFilter().getExclude().get(0);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689180. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(searchField, testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify filters plutoOfficeOnly")
  @TmsLink("28501126")
  public void C28501126_TEST() {
    String searchField = "plutoOfficeOnly";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 4, false);

    Boolean testFieldValue = channels.getPlutoOfficeOnly();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689181. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            searchField, testFieldValue.toString(), "boolean", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify filters kidsMode")
  @TmsLink("28501127")
  public void C28501127_TEST() {
    String searchField = "kidsMode";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 4, false);

    Boolean testFieldValue = channels.getKidsMode();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33739911. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            searchField, testFieldValue.toString(), "boolean", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    boolean allMatch = grpcListChannels.stream().allMatch(c -> c.getKidsMode() == testFieldValue);

    Assert.assertTrue(allMatch);
    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify filters distribution.include")
  @TmsLink("28501128")
  public void C28501128_TEST() {
    String searchField = "distribution.include";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 5, true);

    String testFieldValue = channels.getDistribution().getInclude().get(0);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689182. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(searchField, testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify projection fields")
  public void C336_TEST() {
    String searchField = "kidsMode";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 5, true);

    Boolean testFieldValue = channels.getKidsMode();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage(". CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            searchField, testFieldValue.toString(), "boolean", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - verify filters distribution.exclude")
  @TmsLink("28501129")
  public void C28501129_TEST() {
    String searchField = "distribution.exclude";
    Channels channels = channelsUtils.getChannelWithMainCategory(searchField, 6, false);

    String testFieldValue = channels.getDistribution().getExclude().get(0);
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689183. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(searchField, testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, null, List.of(filter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listChannels = channelsUtils.getDocumentsByKeyValue(searchField, testFieldValue);

    List<Channels> filteredChannels =
        new ArrayList<>(
            listChannels.stream()
                .filter(
                    channel ->
                        channel.getCategories().stream()
                            .anyMatch(category -> category.getCatId().equals(mainCategoryId)))
                .sorted(Comparator.comparing(Channels::getId))
                .toList());

    Assert.assertEquals(grpcListChannels.size(), filteredChannels.size());

    List<Channels> listGrpcChannels =
        channelsUtils.mapGrpcObjectsToPojo(grpcListChannels, Channels.class);

    listGrpcChannels.sort(Comparator.comparing(Channels::getId));

    Assert.assertEquals(listGrpcChannels, filteredChannels);
  }

  @Test
  @Description("GetChannelsList - projection")
  @TmsLink("28501083")
  public void C28501083_TEST() {
    String testField = "activeRegion";
    Channels channels = channelsUtils.getChannelWithMainCategory(testField, 8, false);
    String testFieldValue = channels.getActiveRegion();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33739927. CategoryId: " + mainCategoryId);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilter(testField, testFieldValue, "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> responseGrpcMainChannels =
        mainCategoriesClient
            .getChannelList(
                mainCategoryId, 0, 0, null, List.of(activeRegionFilter), null, List.of(testField))
            .getDocumentsList();

    Assert.assertFalse(responseGrpcMainChannels.isEmpty());

    responseGrpcMainChannels.forEach(
        vod -> {
          Assert.assertEquals(vod.getActiveRegion(), testFieldValue);
          Assert.assertTrue(vod.getName().isEmpty());
          Assert.assertTrue(vod.getCategoriesList().isEmpty());
          Assert.assertTrue(vod.getCustomReferencesList().isEmpty());
          Assert.assertTrue(vod.getDescription().isEmpty());
          Assert.assertFalse(vod.getPlutoOfficeOnly());
          Assert.assertFalse(vod.getKidsMode());
        });
  }

  @Test(dataProvider = "published-plutoOffice-kidsMode-name-sort")
  @Description("GetChannelsList - sort by various fields")
  @TmsLink("28501130")
  public void C28501130_TEST(String sortField, int sort) {
    Channels channels = channelsUtils.getChannelWithMainCategory(sortField, 7, false);
    String testFieldValue = channels.getActiveRegion();
    String mainCategoryId = channels.getCategories().get(0).getCatId();
    Assert.assertFalse(mainCategoryId.isEmpty());

    LogUtils.logInfoMessage("C33689184_TEST. CategoryId: " + mainCategoryId);
    tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort allPagedSort =
        mainCategoriesClient.getAllPagedSort(sortField, sort);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilter("activeRegion", testFieldValue, "string", null);

    tv.pluto.ip.dal.maincategories.MainCategories.GetChannelsListResponse channelListResponse =
        mainCategoriesClient.getChannelList(
            mainCategoryId, 0, 0, List.of(allPagedSort), List.of(activeRegionFilter), null, null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.Channel> grpcListChannels =
        channelListResponse.getDocumentsList();

    List<Channels> listAllChannels =
        channelsUtils.getDocumentsByKeyValue("activeRegion", testFieldValue);

    List<Channels> listChannels =
        listAllChannels.stream()
            .filter(
                c ->
                    c.getCategories().stream()
                        .anyMatch(cat -> cat.getCatId().equals(mainCategoryId)))
            .collect(Collectors.toList());

    List<?> listResponse;

    switch (sortField) {
      case "published":
        if (sort == 1) listChannels.sort(Comparator.comparing(Channels::getPublished));
        else listChannels.sort(Comparator.comparing(Channels::getPublished).reversed());
        listResponse = listChannels.stream().map(Channels::getPublished).toList();
        break;
      case "plutoOfficeOnly":
        if (sort == 1) listChannels.sort(Comparator.comparing(Channels::getPlutoOfficeOnly));
        else listChannels.sort(Comparator.comparing(Channels::getPlutoOfficeOnly).reversed());
        listResponse = listChannels.stream().map(Channels::getPlutoOfficeOnly).toList();
        break;
      case "kidsMode":
        if (sort == 1) listChannels.sort(Comparator.comparing(Channels::getKidsMode));
        else listChannels.sort(Comparator.comparing(Channels::getKidsMode).reversed());
        listResponse = listChannels.stream().map(Channels::getKidsMode).toList();
        break;
      case "name":
        if (sort == 1) listChannels.sort(Comparator.comparing(Channels::getName));
        else listChannels.sort(Comparator.comparing(Channels::getName).reversed());
        listResponse = listChannels.stream().map(Channels::getName).toList();
        break;
      default:
        throw new IllegalArgumentException("Invalid sort field: " + sortField);
    }

    List<?> grpcResponse;
    switch (sortField) {
      case "published":
        grpcResponse =
            grpcListChannels.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getPublished)
                .toList();
        break;
      case "plutoOfficeOnly":
        grpcResponse =
            grpcListChannels.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getPlutoOfficeOnly)
                .toList();
        break;
      case "kidsMode":
        grpcResponse =
            grpcListChannels.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getKidsMode)
                .toList();
        break;
      case "name":
        grpcResponse =
            grpcListChannels.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.Channel::getName)
                .sorted(sort == 1 ? Comparator.naturalOrder() : Comparator.reverseOrder())
                .toList();
        break;
      default:
        throw new IllegalArgumentException("Invalid sort field: " + sortField);
    }

    Assert.assertFalse(listResponse.isEmpty());
    Assert.assertEquals(grpcResponse.size(), listResponse.size());
    Assert.assertEquals(grpcResponse, listResponse);
  }

  @Test(dataProvider = "get-vod-category-list-sort")
  @Description("GetVodCategoriesList - sort by field")
  @TmsLink("28501089")
  public void C28501089_TEST(String sortField, int sortValue) {
    VodCategories vodCategories = vodCategoryUtils.getChannelWithMainCategory(sortField, 1, false);
    String catId = vodCategories.getCategories().get(0).getCatId();
    String activeRegion = vodCategories.getActiveRegion();
    LogUtils.logInfoMessage(
        "C33739835. MainCategoryId: "
            + catId
            + ", activeRegion: "
            + activeRegion
            + ", sortField: "
            + sortField);

    List<tv.pluto.ip.dal.maincategories.MainCategories.GetAllPagedSort> allPagedSort =
        List.of(mainCategoriesClient.getAllPagedSort(sortField, sortValue));

    tv.pluto.ip.dal.maincategories.MainCategories.Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilter("activeRegion", activeRegion, "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
        mainCategoriesClient
            .getVodCategoriesList(
                catId, null, null, null, allPagedSort, List.of(activeRegionFilter), null)
            .getDocumentsList();

    boolean allMatchFilter =
        vodDocsList.stream().allMatch(v -> v.getActiveRegion().equals(activeRegion));
    Assert.assertTrue(allMatchFilter);

    List<VodCategories> getSortedDocumentsByKeyValue =
        vodCategoryUtils.getSortedDocumentsByKeyValue(
            CATEGORY_ID, catId, activeRegion, sortField, sortValue);

    Assert.assertFalse(getSortedDocumentsByKeyValue.isEmpty());

    switch (sortField) {
      case "name":
        /* To lower case name - the reason in DB some bad test data like: My test, My Test, My TEST, MY TEST, MY Test 123 and etc */
        List<String> listDbNames =
            getSortedDocumentsByKeyValue.stream().map(v -> v.getName().toLowerCase()).toList();

        List<String> listGrpcNames =
            vodDocsList.stream().map(v -> v.getName().toLowerCase()).toList();

        Assert.assertFalse(listDbNames.isEmpty());
        Assert.assertEquals(listDbNames, listGrpcNames);
        break;
      case "plutoOfficeOnly":
        List<Boolean> listDbPlutoOfficeOnly =
            getSortedDocumentsByKeyValue.stream().map(VodCategories::getPlutoOfficeOnly).toList();

        List<Boolean> listGrpcPlutoOfficeOnly =
            vodDocsList.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.VodCategory::getPlutoOfficeOnly)
                .toList();

        Assert.assertFalse(listDbPlutoOfficeOnly.isEmpty());
        Assert.assertEquals(listDbPlutoOfficeOnly, listGrpcPlutoOfficeOnly);
        break;
      case "kidsMode":
        List<Boolean> listDbKidsMode =
            getSortedDocumentsByKeyValue.stream().map(VodCategories::getKidsMode).toList();

        List<Boolean> listGrpcKidsMode =
            vodDocsList.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.VodCategory::getKidsMode)
                .toList();

        Assert.assertFalse(listDbKidsMode.isEmpty());
        Assert.assertEquals(listDbKidsMode, listGrpcKidsMode);
        break;
      case "enabled":
        List<Boolean> listDbEnabled =
            getSortedDocumentsByKeyValue.stream().map(VodCategories::getEnabled).toList();

        List<Boolean> listGrpcEnabled =
            vodDocsList.stream()
                .map(tv.pluto.ip.dal.maincategories.MainCategories.VodCategory::getEnabled)
                .toList();

        Assert.assertFalse(listDbEnabled.isEmpty());
        Assert.assertEquals(listDbEnabled, listGrpcEnabled);
        break;
      default:
        throw new IllegalArgumentException("Invalid sort field: " + sortField);
    }
  }

  @Test(dataProvider = "enabled-plutoOfficeOnly-kidsMode-enabled")
  @Description("GetVodCategoriesList - filter by enabled-plutoOfficeOnly-kidsMode")
  @TmsLink("28501090")
  public void C28501090_TEST(String testField) {
    VodCategories vodCategories = vodCategoryUtils.getChannelWithMainCategory(testField, 1, false);
    String catId = vodCategories.getCategories().get(0).getCatId();
    List<VodCategories> getVodCatList =
        vodCategoryUtils.getDocumentsByKeyValueId(CATEGORY_ID, catId);
    boolean filtered;

    if (testField.equals("enabled")) filtered = vodCategories.getEnabled();
    else if (testField.equals("plutoOfficeOnly")) filtered = vodCategories.getPlutoOfficeOnly();
    else filtered = vodCategories.getKidsMode();

    LogUtils.logInfoMessage(
        "C33739837. MainCategoryId: " + catId + ", " + testField + ": " + filtered);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(
            testField, String.valueOf(filtered), "boolean", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
        mainCategoriesClient
            .getVodCategoriesList(catId, null, null, null, null, List.of(filter), null)
            .getDocumentsList();

    boolean allMatchFilter;
    Set<VodCategories> filteredDBSet;

    switch (testField) {
      case "name":
        String name = vodCategories.getName();

        filteredDBSet =
            getVodCatList.stream()
                .filter(v -> v.getName().equals(name))
                .collect(Collectors.toSet());

        allMatchFilter = vodDocsList.stream().allMatch(v -> v.getName().equals(name));
        break;
      case "enabled":
        filteredDBSet =
            getVodCatList.stream()
                .filter(v -> v.getEnabled().equals(filtered))
                .collect(Collectors.toSet());

        allMatchFilter = vodDocsList.stream().allMatch(v -> v.getEnabled() == filtered);
        break;
      case "plutoOfficeOnly":
        filteredDBSet =
            getVodCatList.stream()
                .filter(v -> v.getPlutoOfficeOnly() == filtered)
                .collect(Collectors.toSet());

        allMatchFilter = vodDocsList.stream().allMatch(v -> v.getPlutoOfficeOnly() == filtered);
        break;
      default:
        filteredDBSet =
            getVodCatList.stream()
                .filter(v -> v.getKidsMode() == filtered)
                .collect(Collectors.toSet());

        allMatchFilter = vodDocsList.stream().allMatch(v -> v.getKidsMode() == filtered);
        break;
    }

    Assert.assertFalse(vodDocsList.isEmpty());
    Assert.assertTrue(allMatchFilter);

    Set<VodCategories> setGrpcVodCat =
        vodCategoryUtils.mapGrpcObjectsToPojoSet(vodDocsList, VodCategories.class);

    Assert.assertEquals(setGrpcVodCat, filteredDBSet);
  }

  @Test(dataProvider = "regionFilter-distribution")
  @Description("GetVodCategoriesList - filter by regionFilter-distribution")
  @TmsLink("28501093")
  public void C28501093_TEST(String testField) {
    VodCategories vodCategories = vodCategoryUtils.getChannelWithMainCategory(testField, 1, true);
    String catId = vodCategories.getCategories().get(0).getCatId();

    List<VodCategories> getVodCatList =
        vodCategoryUtils.getDocumentsByKeyValueId(CATEGORY_ID, catId);

    String testFieldValue;

    switch (testField) {
      case "regionFilter.include":
        testFieldValue = vodCategories.getRegionFilter().getInclude().get(0);
        break;
      case "regionFilter.exclude":
        testFieldValue = vodCategories.getRegionFilter().getExclude().get(0);
        break;
      case "distribution.include":
        testFieldValue = vodCategories.getDistribution().getInclude().get(0);
        break;
      case "distribution.exclude":
        testFieldValue = vodCategories.getDistribution().getExclude().get(0);
        break;
      default:
        throw new IllegalArgumentException("Invalid test field: " + testField);
    }

    LogUtils.logInfoMessage(
        "C33739856_TEST. MainCategoryId: " + catId + ", " + testField + ": " + testFieldValue);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(testField, testFieldValue, "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
        mainCategoriesClient
            .getVodCategoriesList(catId, null, null, null, null, List.of(filter), null)
            .getDocumentsList();

    Set<VodCategories> filteredDBSet =
        getVodCatList.stream()
            .filter(
                v -> {
                  switch (testField) {
                    case "regionFilter.include":
                      return v.getRegionFilter().getInclude().contains(testFieldValue);
                    case "regionFilter.exclude":
                      return v.getRegionFilter().getExclude().contains(testFieldValue);
                    case "distribution.include":
                      return v.getDistribution().getInclude().contains(testFieldValue);
                    case "distribution.exclude":
                      return v.getDistribution().getExclude().contains(testFieldValue);
                    default:
                      return false;
                  }
                })
            .collect(Collectors.toSet());

    boolean allMatchFilter =
        vodDocsList.stream()
            .allMatch(
                v -> {
                  switch (testField) {
                    case "regionFilter.include":
                      return v.getRegionFilter().getIncludeList().contains(testFieldValue);
                    case "regionFilter.exclude":
                      return v.getRegionFilter().getExcludeList().contains(testFieldValue);
                    case "distribution.include":
                      return v.getDistribution().getIncludeList().contains(testFieldValue);
                    case "distribution.exclude":
                      return v.getDistribution().getExcludeList().contains(testFieldValue);
                    default:
                      return false;
                  }
                });

    Assert.assertFalse(vodDocsList.isEmpty());
    Assert.assertTrue(allMatchFilter);

    Set<VodCategories> setGrpcVodCat =
        vodCategoryUtils.mapGrpcObjectsToPojoSet(vodDocsList, VodCategories.class);

    Assert.assertEquals(setGrpcVodCat, filteredDBSet);
  }

  @Test
  @Description("GetVodCategoriesList - projection")
  @TmsLink("28501091")
  public void C28501091_TEST() {
    String testField = "name";
    VodCategories vodCategories = vodCategoryUtils.getChannelWithMainCategory(testField, 2, true);
    String catId = vodCategories.getCategories().get(0).getCatId();
    String testFieldValue = vodCategories.getName();

    LogUtils.logInfoMessage(
        "C33739857. MainCategoryId: " + catId + ", " + testField + ": " + testFieldValue);

    tv.pluto.ip.dal.maincategories.MainCategories.Filter filter =
        mainCategoriesClient.mainCategoryFilter(testField, testFieldValue, "string", null);

    List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
        mainCategoriesClient
            .getVodCategoriesList(
                catId, null, null, null, null, List.of(filter), List.of(testField))
            .getDocumentsList();

    Assert.assertFalse(vodDocsList.isEmpty());

    vodDocsList.forEach(
        vod -> {
          Assert.assertEquals(vod.getName(), testFieldValue);
          Assert.assertTrue(vod.getCategoriesList().isEmpty());
          Assert.assertTrue(vod.getCustomReferencesList().isEmpty());
          Assert.assertTrue(vod.getDisplayName().isEmpty());
          Assert.assertTrue(vod.getDescription().isEmpty());
          Assert.assertTrue(vod.getActiveRegion().isEmpty());
          Assert.assertFalse(vod.getPlutoOfficeOnly());
          Assert.assertFalse(vod.getKidsMode());
          Assert.assertFalse(vod.getEnabled());
        });
  }

  @Test(
      dataProvider = "natural-custom",
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = INTERNAL_MESSAGE)
  @TmsLink("28501134")
  @Description("BulkAssignChannelsToMainCategories - different activeRegion")
  public void C28501134_TEST(String order) {
    String mainCat =
        ((MainCategories) mainCategoriesUtils.getDocumentByKeyValue("activeRegion", "us")).getId();

    String channelEs =
        ((Channels) channelsUtils.getDocumentByKeyValue("activeRegion", "es")).getId();

    mainCategoriesClient.bulkAssignChannelsToMainCategoriesResponse(
        mainCat, List.of(channelEs), order);
  }

  @Test(dataProvider = "natural-custom")
  @Description("BulkAssignChannelsToMainCategories - happy path orders")
  @TmsLink("28501131")
  public void C28501131_TEST(String order) {
    Instant startTest = Instant.now().minusSeconds(60);
    String activeRegion = "us";
    Document newMainCat =
        new Document()
            .append("name", "test")
            .append("activeRegion", activeRegion)
            .append("order", 1);
    String mainCat = mainCategoriesUtils.insertDocument(newMainCat);

    List<Document> listCats = Collections.emptyList();

    Document channelOne = channelsUtils.getChannelDoc(listCats, 1, activeRegion);
    Document channelTwo = channelsUtils.getChannelDoc(listCats, 3, activeRegion);
    Document channelThree = channelsUtils.getChannelDoc(listCats, 5, activeRegion);

    List<Document> listChannelsToCreate = List.of(channelOne, channelTwo, channelThree);

    InsertManyResult insertManyResults = channelsUtils.insertDocuments(listChannelsToCreate);
    Map<Integer, BsonValue> insertedIds = insertManyResults.getInsertedIds();
    List<String> listChannelIds =
        insertedIds.values().stream().map(v -> v.asObjectId().getValue().toString()).toList();

    LogUtils.logInfoMessage(
        "C33751926_TEST. CategoryId: "
            + mainCat
            + ", ChannelIds: "
            + listChannelIds
            + ", order: "
            + order);

    tv.pluto.ip.dal.maincategories.MainCategories.BulkAssignChannelsToMainCategoriesResponse
        bulkResponse =
            mainCategoriesClient.bulkAssignChannelsToMainCategoriesResponse(
                mainCat, listChannelIds, order);

    Assert.assertEquals(bulkResponse.getDocumentsCount(), listChannelIds.size());

    List<tv.pluto.ip.dal.maincategories.MainCategories.BulkChannelsMainCategories> bulkDocs =
        bulkResponse.getDocumentsList();

    List<Channels> documentsByIds = channelsUtils.getDocumentsByIds(listChannelIds);

    // delete test data
    channelsUtils.deleteDocuments(listChannelIds);
    mainCategoriesUtils.deleteDocument(mainCat);

    for (int i = 0; i < bulkDocs.size(); i++) {

      tv.pluto.ip.dal.maincategories.MainCategories.BulkChannelsMainCategories bulkDoc =
          bulkDocs.get(i);

      Assert.assertEquals(bulkDoc.getChannelId(), listChannelIds.get(i));
      Assert.assertEquals(bulkDoc.getMainCategoryId(), mainCat);

      Instant updatedChannelResponse = Instant.parse(bulkDoc.getUpdatedAt());
      boolean dateBetweenDates =
          CommonUtils.isDateBetweenDates(
              startTest, Instant.now().plusSeconds(60), updatedChannelResponse);
      Assert.assertTrue(dateBetweenDates);

      Channels channelAfterUpdate =
          documentsByIds.stream()
              .filter(c -> c.getId().equals(bulkDoc.getChannelId()))
              .findFirst()
              .orElseThrow(() -> new NoSuchElementException("Channel not found"));

      Category category =
          channelAfterUpdate.getCategories().stream()
              .filter(cat -> cat.getCatId().equals(mainCat))
              .findFirst()
              .orElseThrow(
                  () -> new NoSuchElementException("Category not found for id: " + mainCat));

      int expectedOrder = i + 1;
      Assert.assertEquals(bulkDoc.getOrder(), expectedOrder);
      Assert.assertEquals(category.getCatId(), mainCat);
      Assert.assertEquals(category.getOrder(), expectedOrder);
    }
  }

  @Test(dataProvider = "natural-custom")
  @Description("BulkAssignChannelsToMainCategoriesResponse - custom order 1 channel")
  @TmsLink("28501133")
  public void C28501133_TEST(String order) {
    Instant startTest = Instant.now().minusSeconds(60);
    String activeRegion = "us";
    Document newMainCat =
        new Document()
            .append("name", "test")
            .append("activeRegion", activeRegion)
            .append("order", 1);

    String mainCat = mainCategoriesUtils.insertDocument(newMainCat);
    String mainCatTwo = mainCategoriesUtils.insertDocument(newMainCat);
    Document catCreate = new Document("catId", new ObjectId(mainCat)).append("order", 2);

    List<Document> listCats = List.of(catCreate);

    Document channelOne = channelsUtils.getChannelDoc(listCats, 1, activeRegion);
    Document channelTwo = channelsUtils.getChannelDoc(listCats, 3, activeRegion);
    Document channelThree = channelsUtils.getChannelDoc(listCats, 5, activeRegion);

    List<Document> listChannelsToCreate = List.of(channelOne, channelTwo, channelThree);
    InsertManyResult insertManyResults = channelsUtils.insertDocuments(listChannelsToCreate);
    Map<Integer, BsonValue> insertedIds = insertManyResults.getInsertedIds();
    List<String> listChannelIds =
        insertedIds.values().stream().map(v -> v.asObjectId().getValue().toString()).toList();

    LogUtils.logInfoMessage(
        "C33796491_TEST. CategoryId: "
            + mainCat
            + ", ChannelIds: "
            + listChannelIds
            + ", order: "
            + order);

    tv.pluto.ip.dal.maincategories.MainCategories.BulkAssignChannelsToMainCategoriesResponse
        bulkResponse =
            mainCategoriesClient.bulkAssignChannelsToMainCategoriesResponse(
                mainCatTwo, listChannelIds, order);

    Assert.assertEquals(bulkResponse.getDocumentsCount(), listChannelIds.size());

    List<tv.pluto.ip.dal.maincategories.MainCategories.BulkChannelsMainCategories> bulkDocs =
        bulkResponse.getDocumentsList();

    List<Channels> documentsByIds = channelsUtils.getDocumentsByIds(listChannelIds);

    // delete test data
    channelsUtils.deleteDocuments(listChannelIds);
    mainCategoriesUtils.deleteDocument(mainCat);
    mainCategoriesUtils.deleteDocument(mainCatTwo);

    for (int i = 0; i < bulkDocs.size(); i++) {

      tv.pluto.ip.dal.maincategories.MainCategories.BulkChannelsMainCategories bulkDoc =
          bulkDocs.get(i);

      Assert.assertEquals(bulkDoc.getChannelId(), listChannelIds.get(i));
      Assert.assertEquals(bulkDoc.getMainCategoryId(), mainCatTwo);

      Instant updatedChannelResponse = Instant.parse(bulkDoc.getUpdatedAt());
      boolean dateBetweenDates =
          CommonUtils.isDateBetweenDates(
              startTest, Instant.now().plusSeconds(60), updatedChannelResponse);
      Assert.assertTrue(dateBetweenDates);

      Channels channelAfterUpdate =
          documentsByIds.stream()
              .filter(c -> c.getId().equals(bulkDoc.getChannelId()))
              .findFirst()
              .orElseThrow(() -> new NoSuchElementException("Channel not found"));

      Category category =
          channelAfterUpdate.getCategories().stream()
              .filter(cat -> cat.getCatId().equals(mainCatTwo))
              .findFirst()
              .orElseThrow(
                  () -> new NoSuchElementException("Category not found for id: " + mainCatTwo));

      int expectedOrder = i + 1;
      Assert.assertEquals(bulkDoc.getOrder(), expectedOrder);
      Assert.assertEquals(category.getCatId(), mainCatTwo);
      Assert.assertEquals(category.getOrder(), expectedOrder);
    }
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "INVALID_ARGUMENT.*")
  @Description("BulkAssignChannelsToMainCategoriesResponse - order is not valid")
  @TmsLink("28501132")
  public void C28501132_TEST() {
    mainCategoriesClient.bulkAssignChannelsToMainCategoriesResponse(
        "67e5ad370e74597db4f8b0cb", List.of("67e5ad370e74597db4f8b0cc"), "test");
  }

  @Test
  @Description("DeleteById - mainCategory no assigned channels or VOD categories")
  @TmsLink("28501077")
  public void C28501077_TEST() {
    MainCategory mainRequest =
        MainCategory.newBuilder()
            .setName("testName")
            .setSlug("testSlug")
            .setActiveRegion("us")
            .build();

    MainCategory response = mainCategoriesClientAuth.createRequest(mainRequest).getDocument();

    String id = response.getId();
    Assert.assertFalse(id.isEmpty());

    long deletedCount = mainCategoriesClientAuth.deleteById(id).getDeletedCount();
    Assert.assertEquals(deletedCount, 1);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_IDS_CATEGORIES)
  @Description("DeleteById - not existing mainCategory")
  @TmsLink("28501078")
  public void C28501078_TEST() {
    String notExistingId = CommonUtils.generateRandomObjectId();
    LogUtils.logInfoMessage(". Not existing Id: " + notExistingId);
    mainCategoriesClientAuth.deleteById(notExistingId);
  }

  @Test
  @Issue("IP-5938")
  @Description("GetVodCategoriesList - regionFilter case insensitive validation.")
  @TmsLink("28501135")
  public void C28501135_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getExistsAndSizeNotZero("categories");
    String catId = vodCategories.getCategories().get(0).getCatId();

    String regionFilterInclude = "regionFilter.include";
    String regionFilterExclude = "regionFilter.exclude";

    String[][] cases = {
      {"US", "GB"},
      {"uS", "gB"},
      {"us", "gb"},
      {"Us", "Gb"}
    };

    Set<VodCategories> expectedFilteredDBSet = null;
    Set<VodCategories> expectedGrpcSet = null;

    for (int i = 0; i < cases.length; i++) {
      String includeRegion = cases[i][0];
      String excludeRegion = cases[i][1];

      LogUtils.logInfoMessage(
          "C34092433: Scenario regionFilter.include/regionFilter.exclude: "
              + includeRegion
              + "/"
              + excludeRegion);

      List<VodCategories> getVodCatList =
          vodCategoryUtils.getDocumentsByKeyValueId(CATEGORY_ID, catId);

      tv.pluto.ip.dal.maincategories.MainCategories.Filter filterInclude =
          mainCategoriesClient.mainCategoryFilter(
              regionFilterInclude, includeRegion, "string", null);
      tv.pluto.ip.dal.maincategories.MainCategories.Filter filterExclude =
          mainCategoriesClient.mainCategoryFilter(
              regionFilterExclude, excludeRegion, "string", null);

      List<tv.pluto.ip.dal.maincategories.MainCategories.VodCategory> vodDocsList =
          mainCategoriesClient
              .getVodCategoriesList(
                  catId, null, null, null, null, List.of(filterInclude, filterExclude), null)
              .getDocumentsList();

      Set<VodCategories> filteredDBSet =
          getVodCatList.stream()
              .filter(
                  v ->
                      v.getRegionFilter().getInclude().stream()
                              .anyMatch(r -> r.equalsIgnoreCase(includeRegion))
                          && v.getRegionFilter().getExclude().stream()
                              .anyMatch(r -> r.equalsIgnoreCase(excludeRegion)))
              .collect(Collectors.toSet());

      boolean allMatchFilter =
          vodDocsList.stream()
              .allMatch(
                  v ->
                      v.getRegionFilter().getIncludeList().stream()
                              .anyMatch(r -> r.equalsIgnoreCase(includeRegion))
                          && v.getRegionFilter().getExcludeList().stream()
                              .anyMatch(r -> r.equalsIgnoreCase(excludeRegion)));

      Assert.assertFalse(
          vodDocsList.isEmpty(),
          "vodDocsList should not be empty for case " + includeRegion + "/" + excludeRegion);
      Assert.assertTrue(
          allMatchFilter, "All docs must match filters for " + includeRegion + "/" + excludeRegion);

      Set<VodCategories> grpcSet =
          vodCategoryUtils.mapGrpcObjectsToPojoSet(vodDocsList, VodCategories.class);

      if (i == 0) {
        expectedFilteredDBSet = filteredDBSet;
        expectedGrpcSet = grpcSet;
      } else {
        Assert.assertEquals(
            expectedFilteredDBSet,
            filteredDBSet,
            "filteredDBSet must be equal for case " + includeRegion + "/" + excludeRegion);

        Assert.assertEquals(
            expectedGrpcSet,
            grpcSet,
            "grpcSet must be equal for case " + includeRegion + "/" + excludeRegion);
      }
    }
  }

  @Test
  @Description(
      "GetAllPaged - should return only main categories associated to at least one channel")
  public void C28891105_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "channel", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(0, 0, sortObjects, filters, true);

    Assert.assertTrue(
        response.getDocumentsCount() > 0,
        "Should return at least one main category associated to channels");

    List<String> categoryIds =
        response.getDocumentsList().stream().map(MainCategory::getId).collect(Collectors.toList());

    Assert.assertFalse(categoryIds.isEmpty(), "Category IDs list should not be empty");

    List<Channels> documentsByIds =
        channelsUtils.getDocumentsByIds("categories.catId", categoryIds);

    List<String> listCatIdsDb =
        documentsByIds.stream()
            .flatMap(c -> c.getCategories().stream())
            .map(Category::getCatId)
            .filter(categoryIds::contains)
            .distinct()
            .collect(Collectors.toList());

    Assert.assertFalse(
        listCatIdsDb.isEmpty(), "Category IDs from list should not be empty from database");

    Collections.sort(categoryIds);
    Collections.sort(listCatIdsDb);

    Assert.assertEquals(
        categoryIds,
        listCatIdsDb,
        "The list of category IDs from response should match those in the database");
  }

  @Test
  @Description(
      "GetAllPaged - should return only main categories associated to channels for a specific activeRegion")
  public void C28891106_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "channel", "string");

    Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilterBody("activeRegion", "us", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter, activeRegionFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(0, 0, sortObjects, filters, true);

    List<String> categoryIds =
        response.getDocumentsList().stream().map(MainCategory::getId).collect(Collectors.toList());

    Assert.assertFalse(categoryIds.isEmpty(), "Category IDs list should not be empty");

    List<Channels> documentsByIds =
        channelsUtils.getDocumentsByIds("categories.catId", categoryIds);

    List<String> listCatIdsDb =
        documentsByIds.stream()
            .filter(c -> c.getActiveRegion().equals("us"))
            .flatMap(c -> c.getCategories().stream())
            .map(Category::getCatId)
            .filter(categoryIds::contains)
            .distinct()
            .collect(Collectors.toList());

    Assert.assertFalse(
        listCatIdsDb.isEmpty(), "Category IDs from list should not be empty from database");

    Collections.sort(categoryIds);
    Collections.sort(listCatIdsDb);

    Assert.assertEquals(
        categoryIds,
        listCatIdsDb,
        "The list of category IDs from response should match those in the database");
  }

  @Test
  @Description("GetAllPaged - gets an Exception when no channels exist for the given activeRegion")
  public void C28891107_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "channel", "string");
    Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilterBody("activeRegion", "xx", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter, activeRegionFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    boolean isExceptionThrown = false;
    try {
      mainCategoriesClient.getAllPagedException(0, 0, sortObjects, filters, true);
    } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
      isExceptionThrown = true;
    }
    Assert.assertTrue(isExceptionThrown, "Expected exception was not thrown");
  }

  @Test
  @Description(
      "GetAllPaged - should return only main categories associated to at least one vod category")
  public void C28891109_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "vod", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(0, 0, sortObjects, filters, true);

    Assert.assertTrue(
        response.getDocumentsCount() > 0,
        "Should return at least one main category associated to vod categories");

    List<String> categoryIds =
        response.getDocumentsList().stream().map(MainCategory::getId).collect(Collectors.toList());

    List<VodCategories> documentsByIds =
        vodCategoryUtils.getDocumentsByIds("categories.catId", categoryIds);

    List<String> listCatIdsDb =
        documentsByIds.stream()
            .flatMap(c -> c.getCategories().stream())
            .map(Categories::getCatId)
            .filter(categoryIds::contains)
            .distinct()
            .collect(Collectors.toList());

    Assert.assertFalse(
        listCatIdsDb.isEmpty(), "Category IDs from list should not be empty from database");

    Collections.sort(categoryIds);
    Collections.sort(listCatIdsDb);

    Assert.assertEquals(
        categoryIds,
        listCatIdsDb,
        "The list of category IDs from response should match those in the database");
  }

  @Test
  @Description(
      "GetAllPaged - should return only main categories associated to vod categories for a specific activeRegion")
  public void C28891111_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "vod", "string");
    Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilterBody("activeRegion", "us", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter, activeRegionFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(0, 0, sortObjects, filters, true);

    Assert.assertTrue(
        response.getDocumentsCount() > 0,
        "Should return at least one main category associated to vod categories");

    List<String> categoryIds =
        response.getDocumentsList().stream().map(MainCategory::getId).collect(Collectors.toList());

    List<VodCategories> documentsByIds =
        vodCategoryUtils.getDocumentsByIds("categories.catId", categoryIds);

    List<String> listCatIdsDb =
        documentsByIds.stream()
            .filter(c -> c.getActiveRegion().equals("us"))
            .flatMap(c -> c.getCategories().stream())
            .map(Categories::getCatId)
            .filter(categoryIds::contains)
            .distinct()
            .collect(Collectors.toList());

    Assert.assertFalse(
        listCatIdsDb.isEmpty(), "Category IDs from list should not be empty from database");

    Collections.sort(categoryIds);
    Collections.sort(listCatIdsDb);

    Assert.assertEquals(
        categoryIds,
        listCatIdsDb,
        "The list of category IDs from response should match those in the database");
  }

  @Test
  @Description(
      "GetAllPaged - should return empty when no vod categories exist for the given activeRegion")
  public void C28891112_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "vod", "string");
    Filter activeRegionFilter =
        mainCategoriesClient.mainCategoryFilterBody("activeRegion", "xxx", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter, activeRegionFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    boolean isExceptionThrown = false;
    try {
      mainCategoriesClient.getAllPagedException(0, 0, sortObjects, filters, true);
    } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
      isExceptionThrown = true;
    }
    Assert.assertTrue(isExceptionThrown, "Expected exception was not thrown");
  }

  @Test
  @Description("GetAllPaged - should return paginated results when associatedTo filter is applied")
  public void C28891113_TEST() {
    MainCategoriesClient mainCategoriesClient =
        new MainCategoriesClient(grpcChannelManager.getChannel(), false);

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilterBody("associatedTo", "vod", "string");
    List<Filter> filters = mainCategoriesClient.listFilters(associatedToFilter);
    List<GetAllPagedSort> sortObjects = mainCategoriesClient.singleListSortObject("name", 1);

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(5, 0, sortObjects, filters, true, List.of("name"));

    List<MainCategory> documentsList = response.getDocumentsList();

    Assert.assertFalse(documentsList.isEmpty(), "Response documents should not be empty");

    List<String> catIds =
        documentsList.stream().map(MainCategory::getId).collect(Collectors.toList());
    List<MainCategories> mainCatIdsDb =
        mainCategoriesUtils.getDocumentsByIdsProjection(catIds, List.of("name"));

    response
        .getDocumentsList()
        .forEach(
            mainCategory -> {
              String name =
                  mainCatIdsDb.stream()
                      .filter(mc -> mc.getId().equals(mainCategory.getId()))
                      .findFirst()
                      .orElseThrow(() -> new NoSuchElementException("Main category not found"))
                      .getName();

              Assert.assertEquals(
                  mainCategory.getName(),
                  name,
                  "Name field should match the projected value from DB");

              Assert.assertEquals(
                  mainCategory.getActiveRegion(),
                  "",
                  "ActiveRegion field should be empty due to projection");
            });
  }

  @Test
  @Description("GetAllPaged - operator filters with associatedTo")
  @TmsLink("29364016")
  public void C29364016_Test() {
    int limit = 25;

    Filter associatedToFilter =
        mainCategoriesClient.mainCategoryFilter("associatedTo", "channel", "string", "and");

    Filter activeRegionUs =
        mainCategoriesClient.mainCategoryFilter("activeRegion", "us", "string", "or");

    Filter activeRegionUS =
        mainCategoriesClient.mainCategoryFilter("activeRegion", "US", "string", "or");

    GetAllPagedResponse response =
        mainCategoriesClient.getAllPaged(
            limit,
            0,
            null,
            List.of(associatedToFilter, activeRegionUs, activeRegionUS),
            false,
            null);

    Assert.assertTrue(response.getDocumentsList().size() <= limit);
    Assert.assertEquals(response.getMetadata().getCurrentOffset(), 0);
    Assert.assertTrue(response.getDocumentsCount() > 0);
    for (MainCategory mainCategory : response.getDocumentsList()) {
      List<Channels> channelsList =
          channelsUtils.getDocumentsByKeyValueId("categories.catId", mainCategory.getId());
      boolean hasChannelInUsRegion =
          channelsList.stream().anyMatch(c -> c.getActiveRegion().equalsIgnoreCase("us"));
      Assert.assertTrue(
          hasChannelInUsRegion,
          "Main category with ID "
              + mainCategory.getId()
              + " does not have associated channels in 'us' region");
    }
  }
}
