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.BasicDBObject;
import com.mongodb.client.model.Collation;
import com.mongodb.client.model.Projections;
import com.plutotv.test.lib.LogUtils;
import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.Issue;
import io.qameta.allure.TmsLink;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.vod_category.VodCategoryClient;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.Filter;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.GetAllPagedResponse;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.GetAllPagedSort;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.GetByIdsRequest;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.GetByIdsResponse;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.UpdateFieldsResponse;
import tv.pluto.ip.dal.vodcategory.VodCategoryOuterClass.VodCategory;
import tv.pluto.mongo.dto.DocumentQuery;
import tv.pluto.mongo.entities.episodes.Episodes;
import tv.pluto.mongo.entities.vod.VodCategories;
import tv.pluto.mongo.entities.vodcategories.Categories;
import tv.pluto.mongo.entities.vodcategoryentries.VodCategoryEntries;
import tv.pluto.mongo.utils.VodCategoryEntriesUtils;
import tv.pluto.mongo.utils.VodCategoryUtils;
import tv.pluto.mongo.utils.episodes.EpisodeUtils;
import tv.pluto.utils.CommonUtils;

public class VodCategoryTestSuite extends BaseTest {
  private VodCategoryClient vodCategoryClient;
  private VodCategoryClient vodCategoryClientAuth;
  private VodCategoryUtils vodCategoryUtils;
  private VodCategoryEntriesUtils vodCategoryEntriesUtils;
  private EpisodeUtils episodeUtils;
  private static final int LIMIT_FIFTY = 50;
  private VodCategories regexVodCategory;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    vodCategoryClient = new VodCategoryClient(grpcChannelManager.getChannel(), false);
    vodCategoryClientAuth = new VodCategoryClient(grpcChannelManager.getChannel(), true);
    vodCategoryUtils = new VodCategoryUtils();
    vodCategoryEntriesUtils = new VodCategoryEntriesUtils();
    episodeUtils = new EpisodeUtils();
    regexVodCategory = vodCategoryUtils.getDocumentWithoutSpecialCharactersInName();
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting ascending by single field")
  @TmsLink("28501627")
  public void C28501627_TEST() {
    Bson sort = orderBy(ascending("_id"));
    List<VodCategories> mongoVodCategories = vodCategoryUtils.getDocuments(20, 10, sort);

    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(GetAllPagedSort.newBuilder().setField("_id").setValue(1).build());
    GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    Assert.assertEquals(mongoVodCategories, grpcVodCategories);
  }

  @Test
  @Description("GetAllPagedResponse - has a new object Metadata")
  @TmsLink("28501639")
  public void C28501639_TEST() {
    int total = 8;
    int offset = 6;

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

    GetAllPagedResponse response =
        vodCategoryClient.getAllPaged(total, offset, grpcSort, null, true);

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

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting ascending by multiple fields")
  @TmsLink("28501628")
  public void C28501628_TEST() {
    Bson sort = orderBy(ascending("_id"), ascending("name"));
    List<VodCategories> mongoVodCategories = vodCategoryUtils.getDocuments(20, 10, sort);

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

    GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    Assert.assertEquals(mongoVodCategories, grpcVodCategories);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sort by name by case insensitive")
  @TmsLink("28501650")
  public void C28501650_TEST(int intSort) {
    int limit = 100;
    String sortName = "name";
    Bson sort;

    if (intSort == 1) sort = orderBy(ascending(sortName));
    else sort = orderBy(descending(sortName));

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

    DocumentQuery documentQuery =
        DocumentQuery.builder()
            .limit(limit)
            .offset(0)
            .sort(sort)
            .collation(collation)
            .projections(include("id", "name"))
            .build();

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getDocumentsWithCollation(documentQuery);

    List<GetAllPagedSort> grpcSort =
        List.of(GetAllPagedSort.newBuilder().setField(sortName).setValue(intSort).build());

    GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(limit, 0, grpcSort, null, null);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    List<String> listNameMongo =
        mongoVodCategories.stream().map(VodCategories::getName).collect(Collectors.toList());
    List<String> listNameGrpc =
        grpcVodCategories.stream().map(VodCategories::getName).collect(Collectors.toList());

    String badData = "AD TEST";
    List<String> listNameMongoFiltered =
        listNameMongo.stream().filter(name -> !name.equalsIgnoreCase(badData)).toList();

    List<String> listNameGrpcFiltered =
        listNameGrpc.stream().filter(name -> !name.equalsIgnoreCase(badData)).toList();

    Assert.assertEquals(listNameMongoFiltered, listNameGrpcFiltered);
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting descending by single field")
  @TmsLink("28501629")
  public void C28501629_TEST() {
    Bson sort = orderBy(descending("_id"));
    List<VodCategories> mongoVodCategories = vodCategoryUtils.getDocuments(20, 10, sort);

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

    GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    mongoVodCategories.forEach(
        v -> v.getCategories().sort(Comparator.comparing(Categories::getId)));
    grpcVodCategories.forEach(v -> v.getCategories().sort(Comparator.comparing(Categories::getId)));

    Assert.assertEquals(mongoVodCategories, grpcVodCategories);
  }

  @Test
  @Description(
      "GetAllPaged - get documents with limit and offset, sorting descending by multiple fields")
  @TmsLink("28501630")
  public void C28501630_TEST() {
    Bson sort = orderBy(descending("_id"), descending("name"));
    List<VodCategories> mongoVodCategories = vodCategoryUtils.getDocuments(20, 10, sort);

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

    GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(20, 10, grpcSort, null, null);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    mongoVodCategories.forEach(
        v -> v.getCategories().sort(Comparator.comparing(Categories::getId)));
    grpcVodCategories.forEach(v -> v.getCategories().sort(Comparator.comparing(Categories::getId)));

    Assert.assertEquals(mongoVodCategories, grpcVodCategories);
  }

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

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

  @Test
  @Description("GetAllPaged - filter valid values")
  @TmsLink("28501631")
  public void C28501631_TEST() {
    VodCategories vodCategory = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("GetAllPaged. MongoDB vodCategory id: " + vodCategory.getId());

    List<Filter> listFiltersBodyInVodCategories =
        vodCategoryClient.filtersBodyInVodCategories(vodCategory);

    GetAllPagedSort sortObject = GetAllPagedSort.newBuilder().setField("name").setValue(1).build();

    List<GetAllPagedSort> listSortObjects = Collections.singletonList(sortObject);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInVodCategories, 1, 0, listSortObjects, null);
    VodCategories mongoDBVodCategory = vodCategoryUtils.getDocumentById(vodCategory.getId());

    VodCategoryOuterClass.VodCategory vodCategoryGrpc =
        getAllPagedClientResponse.getDocumentsList().stream()
            .filter(i -> i.getId().equals(mongoDBVodCategory.getId()))
            .findFirst()
            .get();
    VodCategories clientVodCategories =
        vodCategoryUtils.mapGrpcObjectToPojo(vodCategoryGrpc, VodCategories.class);

    Assert.assertEquals(mongoDBVodCategory, clientVodCategories);
  }

  @Test
  @Description("GetAllPaged - filter kidsMode/plutoOfficeOnly limit 50")
  @TmsLink("28501632")
  public void C28501632_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    Filter kidsFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "kidsMode", vodCategories.getKidsMode().toString(), "boolean", null);
    Filter numberFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "plutoOfficeOnly", vodCategories.getPlutoOfficeOnly().toString(), "boolean", null);
    List<Filter> listFiltersBodyInVodCategories =
        vodCategoryClient.listFiltersBodyInVodCategories(kidsFilter, numberFilter);
    List<GetAllPagedSort> listSortObjects = vodCategoryClient.singleListSortObject("name", 1);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInVodCategories, LIMIT_FIFTY, 0, listSortObjects, null);
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            vodCategory ->
                Assert.assertEquals(
                    vodCategory.getPlutoOfficeOnly(),
                    vodCategories.getPlutoOfficeOnly().booleanValue()));
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            vodCategory ->
                Assert.assertEquals(
                    vodCategory.getKidsMode(), vodCategories.getKidsMode().booleanValue()));

    BasicDBObject basicDBObject = vodCategoryUtils.kidsModeObject(vodCategories);
    basicDBObject.put("plutoOfficeOnly", vodCategories.getPlutoOfficeOnly());

    int vodCategoriesGRPCSize = getAllPagedClientResponse.getDocumentsList().size();
    int vodCategorySize = vodCategoryUtils.getListVodCategories(basicDBObject).size();

    if (vodCategorySize > LIMIT_FIFTY) Assert.assertEquals(LIMIT_FIFTY, vodCategoriesGRPCSize);
    else Assert.assertEquals(vodCategoriesGRPCSize, vodCategorySize);
  }

  @Test
  @Description("GetAllPaged - filter kidsMode/activeRegion limit 50")
  @TmsLink("28500173")
  public void C28500173_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    Filter kidsFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "kidsMode", vodCategories.getKidsMode().toString(), "boolean", null);
    Filter numberFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "activeRegion", vodCategories.getActiveRegion(), "string", null);
    List<Filter> listFiltersBodyInvodCategories =
        vodCategoryClient.listFiltersBodyInVodCategories(kidsFilter, numberFilter);
    List<GetAllPagedSort> listSortObjects = vodCategoryClient.singleListSortObject("name", 1);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInvodCategories, LIMIT_FIFTY, 0, listSortObjects, null);
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            chan -> Assert.assertEquals(chan.getActiveRegion(), vodCategories.getActiveRegion()));
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            chan ->
                Assert.assertEquals(
                    chan.getKidsMode(), vodCategories.getKidsMode().booleanValue()));

    BasicDBObject basicDBObject = vodCategoryUtils.kidsModeObject(vodCategories);
    basicDBObject.put("activeRegion", vodCategories.getActiveRegion());

    int vodCategoriesGRPCSize = getAllPagedClientResponse.getDocumentsList().size();
    int vodCategorySize = vodCategoryUtils.getListVodCategories(basicDBObject).size();

    if (vodCategorySize > LIMIT_FIFTY) Assert.assertEquals(LIMIT_FIFTY, vodCategoriesGRPCSize);
    else Assert.assertEquals(vodCategoriesGRPCSize, vodCategorySize);
  }

  @Test
  @Description("UpdateFields - update the vod category fields")
  @TmsLink("28501633")
  public void C28501633_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    String updatedName = CommonUtils.slightlyModifyString(vodCategories.getName());
    String updatedDisplayName = CommonUtils.slightlyModifyString(vodCategories.getDisplayName());

    VodCategoryOuterClass.VodCategory vodCategory =
        VodCategoryOuterClass.VodCategory.newBuilder()
            .setName(updatedName)
            .setDisplayName(updatedDisplayName)
            .build();

    List<String> fields = List.of("name", "displayName");

    UpdateFieldsResponse getUpdateFieldsGrpcResponse =
        vodCategoryClient.getUpdateFieldsResponse(vodCategories.getId(), vodCategory, fields);

    VodCategories vodGrpcResponse =
        vodCategoryUtils.mapGrpcObjectToPojo(
            getUpdateFieldsGrpcResponse.getDocument(), VodCategories.class);

    VodCategoryOuterClass.VodCategory vodCategoryResponse =
        getUpdateFieldsGrpcResponse.getDocument();
    Assert.assertEquals(vodCategory.getName(), vodCategoryResponse.getName());
    Assert.assertEquals(vodCategory.getDisplayName(), vodCategoryResponse.getDisplayName());

    VodCategories vodCategoryMango = vodCategoryUtils.getDocumentById(vodCategories.getId());
    Assert.assertEquals(vodCategoryMango, vodGrpcResponse);
  }

  @Test
  @Description("UpdateFields - update the vod category fields booleans")
  @TmsLink("28501635")
  public void C28501635_TEST() {
    VodCategories vodCategories;
    vodCategories = vodCategoryUtils.getDocumentById("5c1cd0605f1aa669cb2a3586");

    if (vodCategories == null) vodCategories = vodCategoryUtils.getRandomDocument();

    LogUtils.logInfoMessage("Test vodCategoryId: " + vodCategories.getId());

    List<Boolean> listBooleans = List.of(true, false);
    boolean enabled = listBooleans.get(new Random().nextInt(2));
    boolean plutoOfficeOnly = listBooleans.get(new Random().nextInt(2));

    VodCategoryOuterClass.VodCategory vodCategory =
        VodCategoryOuterClass.VodCategory.newBuilder()
            .setEnabled(enabled)
            .setPlutoOfficeOnly(plutoOfficeOnly)
            .build();

    List<String> fields = List.of("enabled", "plutoOfficeOnly");

    UpdateFieldsResponse getUpdateFieldsGrpcResponse =
        vodCategoryClient.getUpdateFieldsResponse(vodCategories.getId(), vodCategory, fields);

    VodCategories vodGrpcResponse =
        vodCategoryUtils.mapGrpcObjectToPojo(
            getUpdateFieldsGrpcResponse.getDocument(), VodCategories.class);

    VodCategoryOuterClass.VodCategory vodCategoryResponse =
        getUpdateFieldsGrpcResponse.getDocument();
    Assert.assertEquals(enabled, vodCategoryResponse.getEnabled());
    Assert.assertEquals(plutoOfficeOnly, vodCategoryResponse.getPlutoOfficeOnly());

    VodCategories vodCategoryMango = vodCategoryUtils.getDocumentById(vodCategories.getId());
    Assert.assertEquals(vodCategoryMango, vodGrpcResponse);
  }

  @Test
  @Description("GetByEpisodeId - with an episode")
  @TmsLink("28501637")
  public void C28501637_TEST() {
    VodCategoryEntries vodCategoryEntries =
        vodCategoryEntriesUtils.getRandomDocumentWithTheField("episode", true);
    episodeUtils.getDocumentById(vodCategoryEntries.getEpisode());
    Episodes episodes = episodeUtils.getDocumentById(vodCategoryEntries.getEpisode());
    List<String> listVodCategoriesIds =
        episodes.getVodCategoryEntries().stream()
            .filter(Objects::nonNull)
            .map(ObjectId::toString)
            .collect(Collectors.toList());
    List<VodCategoryEntries> listVodCategoryEntriesMango =
        vodCategoryEntriesUtils.getDocumentsByIds(listVodCategoriesIds);
    List<String> listVodCategories =
        listVodCategoryEntriesMango.stream()
            .map(VodCategoryEntries::getVodCategory)
            .collect(Collectors.toList());
    List<VodCategories> listVodCategoryMango =
        vodCategoryUtils.getDocumentsByIds(listVodCategories);

    List<VodCategoryOuterClass.VodCategory> vodCategoryGrpcList =
        vodCategoryClient.getVodGetByEpisodeId(vodCategoryEntries.getEpisode());
    List<VodCategories> listGrpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(vodCategoryGrpcList, VodCategories.class);

    listVodCategoryMango.sort(Comparator.comparing(VodCategories::getId));
    listGrpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    Assert.assertEquals(listVodCategoryMango, listGrpcVodCategories);
  }

  @Test
  @Description("GetAllPagedResponse - has a new object Metadata disable_total_count: false")
  @TmsLink("28501640")
  public void C28501640_TEST() {
    int limit = 10;
    int offset = 1;
    VodCategoryOuterClass.GetAllPagedResponse responseVodCategory =
        vodCategoryClient.getAllPaged(limit, offset, null, null, false);
    long countTotalEpisodes = vodCategoryUtils.getDocumentsCountsInTheCollection();

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

  @Test
  @Description("GetByEpisodeId - with no episode")
  @TmsLink("28501638")
  public void C28501638_TEST() {
    Episodes episodes = episodeUtils.getRandomDocumentWithTheField("vodCategoryEntries", false);
    Assert.assertEquals(0, vodCategoryClient.getVodGetByEpisodeId(episodes.getId()).size());
  }

  @Test
  @Description("Create - a new valid VodCategory")
  @TmsLink("28501641")
  public void C28501641_TEST() {
    String vodCategoryId = createNewCategory().getId();
    VodCategories vodCategoryDb = vodCategoryUtils.getDocumentById(vodCategoryId);
    Assert.assertEquals(vodCategoryId, vodCategoryDb.getId());
  }

  @Test(expectedExceptions = StatusRuntimeException.class)
  @Description("Create - a new valid VodCategory empty document")
  @TmsLink("28501642")
  public void C28501642_TEST() {
    VodCategoryOuterClass.VodCategory vodCategory =
        VodCategoryOuterClass.VodCategory.newBuilder().build();
    vodCategoryClientAuth.createVodCategory(vodCategory).getDocument();
  }

  @Test
  @Description("UpdateFields - a new valid updated VodCategory")
  @TmsLink("28501643")
  public void C28501643_TEST() {
    int order = 0;
    String testValue = "DAL";
    String vodCategoryId = createNewCategory().getId();
    VodCategoryOuterClass.VodCategory vodCategory =
        vodCategoryClient.getVodCategoryById(vodCategoryId).getDocument();

    VodCategoryOuterClass.VodCategory vodCategoryBuilder =
        VodCategoryOuterClass.VodCategory.newBuilder()
            .setId(vodCategoryId)
            .addAllCategories(vodCategory.getCategoriesList())
            .setName(vodCategory.getName() + testValue)
            .setDisplayName(vodCategory.getDisplayName() + testValue)
            .setDescription(vodCategory.getDescription() + testValue)
            .setKidsMode(!vodCategory.getKidsMode())
            .setDistribution(vodCategory.getDistribution())
            .setRegionFilter(vodCategory.getRegionFilter())
            .setOrder(order)
            .setPlutoOfficeOnly(!vodCategory.getPlutoOfficeOnly())
            .build();

    List<String> listUpdatedFields =
        List.of(
            "categories",
            "name",
            "displayName",
            "description",
            "kidsMode",
            "distribution",
            "regionFilter",
            "order",
            "plutoOfficeOnly");

    VodCategoryOuterClass.VodCategory updatedDocument =
        vodCategoryClientAuth
            .getUpdateFieldsResponse(vodCategoryId, vodCategoryBuilder, listUpdatedFields)
            .getDocument();
    Assert.assertEquals(updatedDocument.getId(), vodCategoryBuilder.getId());
    Assert.assertEquals(updatedDocument.getName(), vodCategoryBuilder.getName());
    Assert.assertEquals(updatedDocument.getDisplayName(), vodCategoryBuilder.getDisplayName());
    Assert.assertEquals(updatedDocument.getName(), vodCategoryBuilder.getName());
    Assert.assertEquals(updatedDocument.getDescription(), vodCategoryBuilder.getDescription());
    Assert.assertEquals(updatedDocument.getKidsMode(), vodCategoryBuilder.getKidsMode());
    Assert.assertEquals(updatedDocument.getDistribution(), vodCategoryBuilder.getDistribution());
    Assert.assertEquals(updatedDocument.getRegionFilter(), vodCategoryBuilder.getRegionFilter());
    Assert.assertEquals(order, updatedDocument.getOrder());
    Assert.assertEquals(
        vodCategoryBuilder.getPlutoOfficeOnly(), updatedDocument.getPlutoOfficeOnly());
  }

  @Test
  @Description("UpdateFields - the new response field settings")
  @TmsLink("28501634")
  public void C28501634_TEST() {
    String vodCategoryId = createNewCategory().getId();
    VodCategoryOuterClass.VodCategory vodCategory =
        vodCategoryClient.getVodCategoryById(vodCategoryId).getDocument();

    int totalCount = new Random().nextInt(10);
    boolean setEnabled = new Random().nextBoolean();

    VodCategoryOuterClass.VodSettings.Builder builderSettings =
        vodCategory.getSettings().toBuilder()
            .setAutoPublishStartPosition(0)
            .setEnabled(setEnabled)
            .setTotalCount(totalCount);

    VodCategoryOuterClass.VodCategory vodCategoryBuilder =
        VodCategoryOuterClass.VodCategory.newBuilder()
            .setId(vodCategoryId)
            .setSettings(builderSettings)
            .build();

    List<String> listUpdatedFields = List.of("settings");

    VodCategoryOuterClass.VodCategory updatedDocument =
        vodCategoryClientAuth
            .getUpdateFieldsResponse(vodCategoryId, vodCategoryBuilder, listUpdatedFields)
            .getDocument();
    VodCategoryOuterClass.VodSettings settings = updatedDocument.getSettings();

    Assert.assertEquals(setEnabled, settings.getEnabled());
    Assert.assertEquals(vodCategory.getSettings().getSort().getBy(), settings.getSort().getBy());
    Assert.assertEquals(
        vodCategory.getSettings().getSort().getOrder(), settings.getSort().getOrder());
    Assert.assertEquals(
        vodCategoryBuilder.getSettings().getAutoPublishStartPosition(),
        settings.getAutoPublishStartPosition());
    Assert.assertEquals(totalCount, settings.getTotalCount());
    Assert.assertEquals(
        vodCategory.getSettings().getFilters().getPartnerList().size(),
        settings.getFilters().getPartnerList().size());
    Assert.assertEquals(
        vodCategory.getSettings().getFilters().getAgeRangeList().size(),
        settings.getFilters().getAgeRangeList().size());
    Assert.assertEquals(
        vodCategory.getSettings().getFilters().getRatingList().size(),
        settings.getFilters().getRatingList().size());
    Assert.assertEquals(
        vodCategory.getSettings().getFilters().getGenreList().size(),
        settings.getFilters().getGenreList().size());
    Assert.assertEquals(
        vodCategory.getSettings().getFilters().getSeriesTypeList().size(),
        settings.getFilters().getSeriesTypeList().size());
  }

  private VodCategory createNewCategory() {
    VodCategories vodCategoryDb =
        vodCategoryUtils.getRandomDocumentWithTheField("categories.0", true);

    GetByIdsRequest getByIdsRequest =
        GetByIdsRequest.newBuilder().addAllIds(List.of(vodCategoryDb.getId())).build();

    VodCategory documentGrpc =
        vodCategoryClient.getVodCategoryByIds(getByIdsRequest).getDocumentsList().get(0);
    VodCategory documentGrpcUpdated = documentGrpc.toBuilder().setId("").build();
    VodCategory documentResponse =
        vodCategoryClientAuth.createVodCategory(documentGrpcUpdated).getDocument();

    Assert.assertNotNull(documentResponse.getId());
    Assert.assertFalse(documentResponse.getName().isEmpty());
    Assert.assertFalse(documentResponse.getActiveRegion().isEmpty());
    Assert.assertFalse(documentResponse.getCategoriesList().isEmpty());
    Assert.assertFalse(documentResponse.getId().isEmpty());
    Assert.assertNotEquals(documentGrpc.getId(), documentResponse.getId());

    VodCategories documentById =
        vodCategoryUtils.mapGrpcObjectToPojo(documentGrpc, VodCategories.class);
    VodCategories documentResponseGrpc =
        vodCategoryUtils.mapGrpcObjectToPojo(documentResponse, VodCategories.class);
    documentById.setId(documentResponseGrpc.getId());
    documentById.setCreatedAt(documentResponseGrpc.getCreatedAt());
    documentById.setEnabledAt(documentResponseGrpc.getEnabledAt());
    documentById.setOrder(documentResponseGrpc.getOrder());

    Assert.assertEquals(documentById, documentResponseGrpc);
    return documentResponse;
  }

  @DataProvider(name = "regexSearch")
  public Object[][] regexSearch() {
    return CommonUtils.getRegexpSearch(regexVodCategory.getName());
  }

  @Test(dataProvider = "regexSearch")
  @TmsLink("28501619")
  @Description("GetAllPaged - get vods by name regex")
  public void C28501619_TEST(String regexStr) {
    LogUtils.logInfoMessage(
        "C28501619_TEST: Document name = "
            + regexVodCategory.getName()
            + " , Regex string = "
            + regexStr);

    List<Filter> listFilter =
        List.of(
            new VodCategoryClient(grpcChannelManager.getChannel(), false)
                .vodCategoryFilterBody("name", regexStr, "String", null));

    VodCategoryOuterClass.GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPagedRegex(0, 0, null, listFilter, true);

    List<VodCategories> mappedVodCategoriesList =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertTrue(
        mappedVodCategoriesList.stream()
            .anyMatch(channel -> channel.getId().equals(regexVodCategory.getId())));

    List<VodCategories> vodCategoriesMongo = vodCategoryUtils.getDocumentsByRegex("name", regexStr);

    vodCategoriesMongo.sort(
        Comparator.comparing(VodCategories::getId)
            .thenComparing(
                v ->
                    v.getCategories().stream()
                        .sorted(Comparator.comparing(Categories::getCatId))
                        .map(Categories::getCatId)
                        .map(Object::toString)
                        .collect(Collectors.joining(","))));

    mappedVodCategoriesList.sort(
        Comparator.comparing(VodCategories::getId)
            .thenComparing(
                v ->
                    v.getCategories().stream()
                        .sorted(Comparator.comparing(Categories::getCatId))
                        .map(Categories::getCatId)
                        .map(Object::toString)
                        .collect(Collectors.joining(","))));

    Assert.assertEquals(vodCategoriesMongo, mappedVodCategoriesList);
  }

  @Test
  @Description("GetAllPaged - titleCount")
  @TmsLink("28501644")
  public void C28501644_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    Filter numberFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "activeRegion", vodCategories.getActiveRegion(), "string", null);
    List<Filter> listFiltersBodyInvodCategories = List.of(numberFilter);
    List<GetAllPagedSort> listSortObjects = vodCategoryClient.singleListSortObject("name", 1);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInvodCategories, LIMIT_FIFTY, 0, listSortObjects, null);
    List<String> listCategory =
        getAllPagedClientResponse.getDocumentsList().stream()
            .map(c -> c.getId())
            .collect(Collectors.toList());

    List<VodCategoryEntries> vodCategoryEntriesList =
        vodCategoryEntriesUtils.getDocumentsByIds("vodCategory", listCategory);

    Map<String, Long> idCountDb =
        vodCategoryEntriesList.stream()
            .collect(
                Collectors.groupingBy(VodCategoryEntries::getVodCategory, Collectors.counting()));

    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            category -> {
              if (idCountDb.get(category.getId()) == null) {
                Assert.assertEquals(category.getTitleCount(), 0);
              } else {
                long vodCategorySize = idCountDb.get(category.getId());
                Assert.assertEquals(category.getTitleCount(), vodCategorySize);
              }
            });
  }

  @Test
  @Description("GetAllPaged - categories have name")
  @TmsLink("28501645")
  public void C28501645_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    Filter numberFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "activeRegion", vodCategories.getActiveRegion(), "string", null);
    List<Filter> listFiltersBodyInvodCategories = List.of(numberFilter);
    List<GetAllPagedSort> listSortObjects = vodCategoryClient.singleListSortObject("name", 1);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInvodCategories, LIMIT_FIFTY, 0, listSortObjects, null);
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            category ->
                category
                    .getCategoriesList()
                    .forEach(cat -> Assert.assertNotNull(category.getName())));
  }

  @Test
  @Description("GetAllPaged - categories sorted in alphabetical order")
  @TmsLink("28501646")
  public void C28501646_TEST() {
    VodCategories vodCategories =
        vodCategoryUtils.getRandomDocumentWithTheField("categories.0", true);
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    Filter numberFilter =
        vodCategoryClient.vodCategoryFilterBody(
            "activeRegion", vodCategories.getActiveRegion(), "string", null);
    List<Filter> listFiltersBodyInvodCategories = List.of(numberFilter);
    List<GetAllPagedSort> listSortObjects =
        vodCategoryClient.singleListSortObject("categoryName", 1);

    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            listFiltersBodyInvodCategories, 10, 0, listSortObjects, null);
    getAllPagedClientResponse
        .getDocumentsList()
        .forEach(
            category -> {
              List<VodCategoryOuterClass.Category> categoriesList = category.getCategoriesList();
              if (categoriesList.size() > 1) {
                List<VodCategoryOuterClass.Category> listBeforeSorting =
                    new ArrayList<>(categoriesList);
                listBeforeSorting.sort(
                    Comparator.comparing(VodCategoryOuterClass.Category::getName));
                Assert.assertEquals(categoriesList, listBeforeSorting);
              }
            });
  }

  @Test
  @Description("GetAllPaged - return correct categories with the correct name")
  @TmsLink("28501649")
  public void C28501649_TEST() {
    GetAllPagedResponse getAllPagedClientResponse =
        vodCategoryClient.getAllPagedResponse(
            Collections.emptyList(), 1, 0, Collections.emptyList(), null);
    VodCategoryOuterClass.VodCategory vodCategory =
        getAllPagedClientResponse.getDocumentsList().get(0);

    String vodId = vodCategory.getId();

    VodCategories mongoDBVodCategory = vodCategoryUtils.getDocumentById(vodId);

    List<VodCategoryOuterClass.Category> categoriesList = vodCategory.getCategoriesList();
    Set<Categories> categories = new HashSet<>(mongoDBVodCategory.getCategories());
    Set<Categories> grpcCategories =
        vodCategoryUtils.mapGrpcObjectsToPojoSet(categoriesList, Categories.class);

    Assert.assertEquals(categories, grpcCategories);
    Assert.assertEquals(mongoDBVodCategory.getName(), vodCategory.getName());
    Assert.assertEquals(mongoDBVodCategory.getDisplayName(), vodCategory.getDisplayName());
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by activeRegion")
  @TmsLink("28501659")
  public void C28501659_TEST(int sortValue) {
    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("activeRegion").setValue(sortValue).build());

    VodCategoryOuterClass.GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(0, 0, grpcSort, null, true);
    Assert.assertFalse(response.getDocumentsList().isEmpty());

    List<String> activeRegionList =
        response.getDocumentsList().stream()
            .map(VodCategory::getActiveRegion)
            .collect(Collectors.toList());
    List<String> sortedList = new ArrayList<>(activeRegionList);

    if (sortValue == 1) sortedList.sort(Comparator.naturalOrder());
    else sortedList.sort(Comparator.reverseOrder());

    Assert.assertEquals(activeRegionList, sortedList);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by categoryName")
  @TmsLink("28501660")
  public void C28501660_TEST(int sortValue) {
    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("categoryName").setValue(sortValue).build());

    VodCategoryOuterClass.GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(5, 0, grpcSort, null, true);
    Assert.assertFalse(response.getDocumentsList().isEmpty());

    List<String> listSortedNames = new ArrayList<>();
    List<String> listNotSortedNames = new ArrayList<>();

    for (VodCategory vodCategory : response.getDocumentsList()) {
      List<VodCategoryOuterClass.Category> immutableCategoriesList =
          vodCategory.getCategoriesList();
      if (immutableCategoriesList.isEmpty()) {
        continue;
      }
      List<VodCategoryOuterClass.Category> categoriesList =
          new ArrayList<>(immutableCategoriesList);
      listNotSortedNames.add(categoriesList.get(0).getName());

      if (sortValue == 1)
        categoriesList.sort(
            Comparator.comparing(
                VodCategoryOuterClass.Category::getName, Comparator.naturalOrder()));
      else
        categoriesList.sort(
            Comparator.comparing(
                VodCategoryOuterClass.Category::getName, Comparator.reverseOrder()));

      listSortedNames.add(categoriesList.get(0).getName());
    }

    Assert.assertEquals(listSortedNames, listNotSortedNames);
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sorting by titleCount")
  @TmsLink("28501661")
  public void C28501661_TEST(int sortValue) {
    List<GetAllPagedSort> grpcSort =
        Collections.singletonList(
            GetAllPagedSort.newBuilder().setField("titleCount").setValue(sortValue).build());

    VodCategoryOuterClass.GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(0, 0, grpcSort, null, true);
    Assert.assertFalse(response.getDocumentsList().isEmpty());

    List<Integer> activeRegionList =
        response.getDocumentsList().stream()
            .map(VodCategory::getTitleCount)
            .collect(Collectors.toList());
    List<Integer> sortedList = new ArrayList<>(activeRegionList);

    if (sortValue == 1) sortedList.sort(Comparator.naturalOrder());
    else sortedList.sort(Comparator.reverseOrder());

    Assert.assertEquals(activeRegionList, sortedList);
  }

  @Test
  @Description("GetAllPaged - very the titleCount field")
  @TmsLink("28501662")
  public void C28501662_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    String id = vodCategories.getId();
    List<Filter> listFilter =
        List.of(
            new VodCategoryClient(grpcChannelManager.getChannel(), false)
                .vodCategoryFilterBody("_id", id, "string", null));

    VodCategoryOuterClass.GetAllPagedResponse response =
        new VodCategoryClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(1, 0, null, listFilter, true);
    Assert.assertFalse(response.getDocumentsList().isEmpty());

    int titleCount = response.getDocumentsList().get(0).getTitleCount();
    int vodCategoryEntriesSize =
        vodCategoryEntriesUtils.getDocumentsByFieldAndId("vodCategory", id).size();

    Assert.assertEquals(vodCategoryEntriesSize, titleCount);
  }

  @Test
  @Description("GetPopulatedById - happy path")
  @TmsLink("28501647")
  public void C28501647_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    LogUtils.logInfoMessage("C28501647_TEST. Test vodCategories id: " + vodCategories.getId());

    VodCategoryOuterClass.VodCategoryPopulated response =
        vodCategoryClient.getPopulatedById(vodCategories.getId()).getDocument();

    List<Categories> setDBCategories = new ArrayList<>(vodCategories.getCategories());
    setDBCategories.sort(Comparator.comparing(Categories::getId));
    Set<Categories> setGrpcCategories =
        vodCategoryUtils.mapGrpcObjectsToPojoSet(response.getCategoriesList(), Categories.class);
    List<Categories> sortedGrpcCategories = new ArrayList<>(setGrpcCategories);
    sortedGrpcCategories.sort(Comparator.comparing(Categories::getId));

    Assert.assertEquals(setDBCategories, sortedGrpcCategories);

    Assert.assertEquals(response.getId(), vodCategories.getId());
    Assert.assertEquals(response.getName(), vodCategories.getName());
    Assert.assertEquals(response.getOrder(), vodCategories.getOrder());
    Assert.assertEquals(response.getActiveRegion(), vodCategories.getActiveRegion());
    Assert.assertEquals(response.getDisplayName(), vodCategories.getDisplayName());
    Assert.assertEquals(response.getKidsMode(), vodCategories.getKidsMode());
    Assert.assertNotNull(response.getCreatedAt());
    Assert.assertNotNull(response.getDistribution());
    Assert.assertEquals(response.getDisplayName().length(), response.getTitleCount());

    response
        .getVodCategoryEntriesList()
        .forEach(
            vod -> {
              Boolean hasAvailable = vod.getSeries().hasAvailabilityWindows();
              Assert.assertNotNull(hasAvailable);
            });

    response
        .getCategoriesList()
        .forEach(
            c -> {
              Integer order = c.getCategoryDetails().getOrder();
              Assert.assertNotNull(order);
            });
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategory document for requested ID not found")
  @Description("GetPopulatedById - invalid id")
  @TmsLink("28501648")
  public void C28501648_TEST() {
    vodCategoryClient.getPopulatedById("00057c2a3fd131544b000000").getDocument();
  }

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

    VodCategories vodCategories = vodCategoryUtils.getSortedDocumentByField("order", -1);
    String vodId = vodCategories.getId();

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

    VodCategoryOuterClass.UpdateOrderResponse updateResponse =
        vodCategoryClient.updateOrder(List.of(docOrder));
    Assert.assertEquals(vodId, updateResponse.getDocuments(0).getId());
    Assert.assertEquals(newOrder, updateResponse.getDocuments(0).getOrder());

    VodCategoryOuterClass.VodCategory vodDocGrpc =
        vodCategoryClient.getVodCategoryById(vodId).getDocument();
    Assert.assertEquals(newOrder, vodDocGrpc.getOrder());
  }

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

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

    List<VodCategories> listVodCategories = vodCategoryUtils.getDocuments(2);
    String vodIdOne = listVodCategories.get(0).getId();
    String vodIdTwo = listVodCategories.get(1).getId();

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

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

    List<VodCategoryOuterClass.UpdateOrderElement> listDocs = List.of(docOneOrder, docTwoOrder);
    VodCategoryOuterClass.UpdateOrderResponse updateResponse =
        vodCategoryClient.updateOrder(listDocs);

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

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

    Assert.assertEquals(
        newOrder1, vodCategoryClient.getVodCategoryById(vodIdOne).getDocument().getOrder());
    Assert.assertEquals(
        newOrder2, vodCategoryClient.getVodCategoryById(vodIdTwo).getDocument().getOrder());
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: Category with ID 58c4a2030da56df862000000 not found")
  @Description("UpdateOrder - invalid id and not existed order number")
  @TmsLink("28501655")
  public void C28501655_TEST() {
    List<Integer> order = vodCategoryUtils.getDistinctListOfTheField("order", Integer.class);
    int validOrder = CommonUtils.listMissingIntegerFromListInOrder(order, 2).get(0);

    VodCategoryOuterClass.UpdateOrderElement docOrder =
        VodCategoryOuterClass.UpdateOrderElement.newBuilder()
            .setId("58c4a2030da56df862000000")
            .setOrder(validOrder)
            .build();

    vodCategoryClient.updateOrder(List.of(docOrder));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: Category with ID 58c4a2030da56df862000000 not found")
  @Description("UpdateOrder - invalid id and existed order number")
  @TmsLink("28501653")
  public void C28501653_TEST() {
    List<Integer> order = vodCategoryUtils.getDistinctListOfTheField("order", Integer.class);

    VodCategoryOuterClass.UpdateOrderElement docOrder =
        VodCategoryOuterClass.UpdateOrderElement.newBuilder()
            .setId("58c4a2030da56df862000000")
            .setOrder(order.get(1))
            .build();

    vodCategoryClient.updateOrder(List.of(docOrder));
  }

  @Test
  @Description("UpdateOrder - empty intileChannel")
  @TmsLink("28501656")
  public void C28501656_TEST() {
    String intileChannel = "";
    VodCategories vodCategories =
        vodCategoryUtils.getRandomDocumentWithTheField("categories.0", true);
    LogUtils.logInfoMessage("Random vodCategoryId: " + vodCategories.getId());

    VodCategoryOuterClass.VodCategory vodCategory =
        VodCategoryOuterClass.VodCategory.newBuilder().setIntileChannel(intileChannel).build();

    UpdateFieldsResponse getUpdateFieldsGrpcResponse =
        vodCategoryClient.getUpdateFieldsResponse(
            vodCategories.getId(), vodCategory, List.of("intileChannel"));

    Assert.assertEquals(
        getUpdateFieldsGrpcResponse.getDocument().getIntileChannel(), intileChannel);

    VodCategoryOuterClass.VodCategory revert =
        VodCategoryOuterClass.VodCategory.newBuilder()
            .setIntileChannel(vodCategories.getIntileChannel())
            .build();
    vodCategoryClient.getUpdateFieldsResponse(
        vodCategories.getId(), revert, List.of("intileChannel"));
  }

  @Test
  @Description("GetVodAutoPublishingSettings - happy path")
  @TmsLink("28501657")
  public void C28501657_TEST() {
    VodCategories vodCategories = vodCategoryUtils.getRandomDocument();
    VodCategoryOuterClass.GetVodAutoPublishingSettingsResponse response =
        vodCategoryClient.getVodAutoPublishingSettings(vodCategories.getId());
    VodCategoryOuterClass.VodSettings document = response.getDocument();
    Assert.assertNotNull(document.getFilters());
    Assert.assertNotNull(document.getSort());
    Assert.assertTrue(document.getTotalCount() >= 0);
    Assert.assertTrue(document.getAutoPublishStartPosition() >= 0);
    String enabled = String.valueOf(document.getEnabled());
    Assert.assertTrue(enabled.equals("true") || enabled.equals("false"));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategory document for requested ID not found")
  @Description("GetVodAutoPublishingSettings - negative scenario")
  @TmsLink("28501658")
  public void C28501658_TEST() {
    String invalidId = "0000dce073ac1fec2fc00000";
    vodCategoryClient.getVodAutoPublishingSettings(invalidId);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("GetById - invalid id")
  @TmsLink("28501663")
  public void C28501663_TEST() {
    vodCategoryClient.getById("dal");
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetById - incorrect id")
  @TmsLink("28501664")
  public void C28501664_TEST() {
    vodCategoryClient.getById(INVALID_ID);
  }

  @Test
  @Description("GetById - happy path")
  @TmsLink("28501665")
  public void C28501665_TEST() {
    VodCategories mongoVodCategory =
        vodCategoryUtils.getRandomDocumentWithTheField("categories.0", true);
    String testVodCatId = mongoVodCategory.getId();
    LogUtils.logInfoMessage("Test VodCategory id: " + testVodCatId);
    VodCategory vodCateGrpc = vodCategoryClient.getById(testVodCatId).getDocument();
    VodCategories grpcVod = vodCategoryUtils.mapGrpcObjectToPojo(vodCateGrpc, VodCategories.class);

    Assert.assertEquals(mongoVodCategory.getId(), testVodCatId);
    Assert.assertEquals(mongoVodCategory, grpcVod);
  }

  @Test
  @Description("GetAllPaged - Add region_filter_query")
  @TmsLink("28501667")
  public void C28501667_TEST() {
    Bson sort = orderBy(ascending("_id"));

    BasicDBObject mongoFilter = new BasicDBObject();
    mongoFilter.put("regionFilter.include", new BasicDBObject("$in", java.util.List.of("US")));
    mongoFilter.put("regionFilter.exclude", new BasicDBObject("$in", java.util.List.of("GB")));

    int limit = 1;
    int offset = 0;

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getListVOD(mongoFilter, limit, offset, sort);

    Assert.assertFalse(mongoVodCategories.isEmpty());

    String includeRegion = "US";
    String excludeRegion = "GB";
    VodCategoryOuterClass.RegionFilter regionFilterQuery =
        VodCategoryOuterClass.RegionFilter.newBuilder()
            .addInclude(includeRegion)
            .addExclude(excludeRegion)
            .build();

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

    GetAllPagedResponse response =
        vodCategoryClient.getAllPagedResponse(
            Collections.emptyList(), limit, offset, grpcSort, regionFilterQuery);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertEquals(mongoVodCategories, grpcVodCategories);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: VodCategory documents not found")
  @Description("GetAllPaged - incorrect region_filter_query")
  @TmsLink("28501666")
  public void C28501666_TEST() {

    VodCategoryOuterClass.RegionFilter regionFilterQuery =
        VodCategoryOuterClass.RegionFilter.newBuilder().addInclude("US1").addExclude("GB1").build();

    vodCategoryClient.getAllPagedResponse(
        Collections.emptyList(), 1, 0, Collections.emptyList(), regionFilterQuery);
  }

  @Test
  @Description("GetByIds - Happy path")
  @TmsLink("28501668")
  public void C28501668_TEST() {
    int limit = 2;

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    int offset = 0;

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getByIds(vodCategoryIds, limit, offset, null, null);

    GetByIdsRequest request = GetByIdsRequest.newBuilder().addAllIds(vodCategoryIds).build();

    GetByIdsResponse response = vodCategoryClient.getVodCategoryByIds(request);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertFalse(mongoVodCategories.isEmpty());
    Assert.assertFalse(grpcVodCategories.isEmpty());

    Assert.assertEquals(
        mongoVodCategories, grpcVodCategories, "The mongoDB and gRPC VodCategories are not equal!");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: Cast to ObjectId failed for value \"Peñarol & Shakhtar Donetsk\" .*")
  @Description("GetByIds - Attempt to get a VodCategory with an non existent id")
  @TmsLink("28501669")
  public void C28501669_TEST() {
    String nonExistentId = "Peñarol & Shakhtar Donetsk";

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(List.of(nonExistentId)).build();

    vodCategoryClient.getVodCategoryByIds(request);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: VodCategory documents for requested IDs not found")
  @Description("GetByIds - Attempt to get a VodCategory without an id")
  @TmsLink("28501670")
  public void C28501670_TEST() {
    GetByIdsRequest request = GetByIdsRequest.newBuilder().build();

    vodCategoryClient.getVodCategoryByIds(request);
  }

  @Test
  @Description("GetByIds - Ascending Sorting Order validation")
  @TmsLink("28501671")
  public void C28501671_TEST() {
    int limit = 2;
    int sortOrder = 1;

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    String[] sortFields = new String[] {"_id", "name", "displayName"};
    Bson sort = orderBy(ascending(sortFields));

    int offset = 0;

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getByIds(vodCategoryIds, limit, offset, sort, null);

    GetAllPagedSort idSort =
        GetAllPagedSort.newBuilder().setField("_id").setValue(sortOrder).build();
    GetAllPagedSort nameSort =
        GetAllPagedSort.newBuilder().setField("name").setValue(sortOrder).build();
    GetAllPagedSort displayNameSort =
        GetAllPagedSort.newBuilder().setField("displayName").setValue(sortOrder).build();

    List<GetAllPagedSort> grpcSort = List.of(idSort, nameSort, displayNameSort);

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(vodCategoryIds).addAllSort(grpcSort).build();

    GetByIdsResponse response = vodCategoryClient.getVodCategoryByIds(request);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertFalse(mongoVodCategories.isEmpty());
    Assert.assertFalse(grpcVodCategories.isEmpty());

    Assert.assertEquals(
        mongoVodCategories, grpcVodCategories, "The mongoDB and gRPC VodCategories are not equal!");
  }

  @Test
  @Description("GetByIds - Descending Sorting Order validation")
  @TmsLink("28501672")
  public void C28501672_TEST() {
    int limit = 2;
    int sortOrder = -1;

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    String[] sortFields = new String[] {"_id", "name", "displayName"};
    Bson sort = orderBy(descending(sortFields));

    int offset = 0;

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getByIds(vodCategoryIds, limit, offset, sort, null);

    GetAllPagedSort idSort =
        GetAllPagedSort.newBuilder().setField("_id").setValue(sortOrder).build();
    GetAllPagedSort nameSort =
        GetAllPagedSort.newBuilder().setField("name").setValue(sortOrder).build();
    GetAllPagedSort displayNameSort =
        GetAllPagedSort.newBuilder().setField("displayName").setValue(sortOrder).build();

    List<GetAllPagedSort> grpcSort = List.of(idSort, nameSort, displayNameSort);

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(vodCategoryIds).addAllSort(grpcSort).build();

    GetByIdsResponse response = vodCategoryClient.getVodCategoryByIds(request);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertFalse(mongoVodCategories.isEmpty());
    Assert.assertFalse(grpcVodCategories.isEmpty());

    Assert.assertEquals(
        mongoVodCategories, grpcVodCategories, "The mongoDB and gRPC VodCategories are not equal!");
  }

  @Test
  @Description("GetByIds - Projection validation")
  @TmsLink("28501673")
  public void C28501673_TEST() {
    int limit = 2;

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    List<String> projectionFields = List.of("_id", "name", "displayName");

    Bson projection = Projections.fields(Projections.include(projectionFields));

    int offset = 0;

    List<VodCategories> mongoVodCategories =
        vodCategoryUtils.getByIds(vodCategoryIds, limit, offset, null, projection);

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder()
            .addAllIds(vodCategoryIds)
            .addAllProjection(projectionFields)
            .build();

    GetByIdsResponse response = vodCategoryClient.getVodCategoryByIds(request);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    Assert.assertFalse(mongoVodCategories.isEmpty());
    Assert.assertFalse(grpcVodCategories.isEmpty());

    Assert.assertEquals(
        mongoVodCategories, grpcVodCategories, "The mongoDB and gRPC VodCategories are not equal!");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: One or more provided sort values no not match 1 or -1.")
  @Issue("IP-5930")
  @Description("GetByIds - Invalid sort order")
  @TmsLink("28501674")
  public void C28501674_TEST() {
    int limit = 2;
    int invalidSortOrder = 10;

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    GetAllPagedSort idSort =
        GetAllPagedSort.newBuilder().setField("_id").setValue(invalidSortOrder).build();

    List<GetAllPagedSort> grpcSort = List.of(idSort);

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(vodCategoryIds).addAllSort(grpcSort).build();

    vodCategoryClient.getVodCategoryByIds(request);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: One or more provided sort attributes are not contained within the table/collection. .*")
  @Issue("IP-5930")
  @Description("GetByIds - Invalid sort field")
  @TmsLink("28501675")
  public void C28501675_TEST() {
    int limit = 2;
    int sortOrder = 1;
    String invalidSortField = "Peñarol & Shakhtar Donetsk";

    List<VodCategories> vodCategoryList = vodCategoryUtils.getRandomDocuments(limit);

    Assert.assertEquals(
        vodCategoryList.size(), limit, "The size of the list is not equal to the filter limit");

    List<String> vodCategoryIds = vodCategoryList.stream().map(VodCategories::getId).toList();

    GetAllPagedSort idSort =
        GetAllPagedSort.newBuilder().setField(invalidSortField).setValue(sortOrder).build();

    List<GetAllPagedSort> grpcSort = List.of(idSort);

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(vodCategoryIds).addAllSort(grpcSort).build();

    vodCategoryClient.getVodCategoryByIds(request);
  }

  @Test
  @Description("GetAllPaged - NOR Operator with Valid Values")
  @TmsLink("28501676")
  public void C28501676_TEST() {
    VodCategoryClient vodCategoryClient =
        new VodCategoryClient(grpcChannelManager.getChannel(), false);

    List<Filter> listFilter =
        List.of(
            vodCategoryClient.vodCategoryFilterBody(
                "distribution.include", "ctv", "string", "NOR"));

    BasicDBObject query =
        new BasicDBObject(
            "$nor",
            List.of(
                new BasicDBObject("distribution.include", "ctv"),
                new BasicDBObject("isArchived", true)));

    List<VodCategories> mongoVodCategories = vodCategoryUtils.getListVodCategories(query);

    GetAllPagedResponse response =
        vodCategoryClient.getAllPaged(mongoVodCategories.size() + 1, 0, null, listFilter, true);

    List<VodCategories> grpcVodCategories =
        vodCategoryUtils.mapGrpcObjectsToPojo(response.getDocumentsList(), VodCategories.class);

    mongoVodCategories.sort(Comparator.comparing(VodCategories::getId));
    grpcVodCategories.sort(Comparator.comparing(VodCategories::getId));

    Assert.assertFalse(mongoVodCategories.isEmpty(), "Mongo result is empty.");
    Assert.assertFalse(grpcVodCategories.isEmpty(), "gRPC result is empty.");
    Assert.assertEquals(
        mongoVodCategories, grpcVodCategories, "Mongo and gRPC results do not match.");
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: VodCategory documents not found")
  @Description("GetAllPaged - NOR and OR filters with valid values resulting in NOT_FOUND")
  @TmsLink("28501677")
  public void C28501677_TEST() {

    vodCategoryClient.getAllPagedResponse(
        List.of(
            vodCategoryClient.vodCategoryFilterBody(
                "distribution.include", "validValue", "string", "NOR"),
            vodCategoryClient.vodCategoryFilterBody(
                "distribution.include", "validValue", "string", "OR")),
        10,
        0,
        Collections.emptyList(),
        null);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "INTERNAL: Operator property should be only AND, OR, or NOR.")
  @Description("GetAllPaged - Invalid operator in filter resulting in INTERNAL error")
  @TmsLink("28501678")
  public void C28501678_TEST() {

    List<VodCategoryOuterClass.Filter> listFilters =
        List.of(
            vodCategoryClient.vodCategoryFilterBody(
                "distribution.include", "ctv", "string", "NOR1"));

    vodCategoryClient.getAllPagedResponse(listFilters, 10, 0, Collections.emptyList(), null);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: VodCategory documents not found")
  @Description("GetAllPaged - Non-existent field in filter resulting in  error")
  @TmsLink("28501679")
  public void C28501679_TEST() {

    List<VodCategoryOuterClass.Filter> listFilters =
        List.of(
            vodCategoryClient.vodCategoryFilterBody("nonExistentField", "value", "string", "AND"));
    vodCategoryClient.getAllPagedResponse(listFilters, 10, 0, Collections.emptyList(), null);
  }
}
