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

import static com.mongodb.client.model.Projections.include;
import static tv.pluto.ip.dal.clip.Clips.Clip;
import static tv.pluto.ip.dal.clip.Clips.Source;
import static tv.pluto.mongo.utils.MongoUtils.INVALID_ID_VALUE;

import com.google.gson.GsonBuilder;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.Filters;
import com.plutotv.test.lib.LogUtils;
import com.plutotv.test.lib.ttfb.grpc.GrpcCall;
import com.plutotv.test.lib.ttfb.grpc.TTFBGrpcValidator;
import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.Issue;
import io.qameta.allure.Issues;
import io.qameta.allure.TmsLink;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import net.datafaker.Faker;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.everit.json.schema.Schema;
import org.everit.json.schema.loader.SchemaLoader;
import org.json.JSONObject;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.testng.asserts.SoftAssert;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.clips.ClipsClient;
import tv.pluto.grpc.episodes.EpisodesClient;
import tv.pluto.grpc.recommendation.RecommendationClient;
import tv.pluto.grpc.utils.ProtoJsonUtil;
import tv.pluto.ip.dal.clip.Clips.Filter;
import tv.pluto.ip.dal.clip.Clips.GetAllPagedResponse;
import tv.pluto.ip.dal.clip.Clips.GetAllPagedSort;
import tv.pluto.ip.dal.recommendation.Recommendation;
import tv.pluto.mongo.dto.ContentFeedQuery;
import tv.pluto.mongo.entities.cleanup.Cleanup;
import tv.pluto.mongo.entities.clips.Clips;
import tv.pluto.mongo.entities.clips.IdUpdated;
import tv.pluto.mongo.entities.common.ObjectIdContentIdSet;
import tv.pluto.mongo.entities.episodes.Episodes;
import tv.pluto.mongo.entities.partners.Partners;
import tv.pluto.mongo.utils.CleanupsUtils;
import tv.pluto.mongo.utils.ClipsUtils;
import tv.pluto.mongo.utils.PartnersUtils;
import tv.pluto.mongo.utils.episodes.EpisodeUtils;
import tv.pluto.utils.CommonUtils;

public class ClipsTestSuite extends BaseTest {
  private ClipsClient clipsClient;
  private ClipsClient clipsClientAuth;
  private RecommendationClient recommendationClient;
  private ClipsUtils clipsUtils;
  private CleanupsUtils cleanupsUtils;
  private PartnersUtils partnersUtils;
  private EpisodeUtils episodeUtils;
  private static final String CLIP_ID_FOR_UPDATE = "60e6e1d5d96ddc0013147e98";
  private final DateTimeFormatter DATE_TIME_FORMAT =
      DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS'Z'", Locale.US);
  private final DateTimeFormatter DATE_TIME_FORMATTER_RESPONSE =
      DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.US);
  private String createdClipId = "";
  private List<String> createdClipsIds = new ArrayList<>();
  private Clips testClip;
  private Clips regexClip;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    clipsClientAuth = new ClipsClient(grpcChannelManager.getChannel(), true);
    clipsClient = new ClipsClient(grpcChannelManager.getChannel(), false);
    recommendationClient = new RecommendationClient(grpcChannelManager.getChannel());
    clipsUtils = new ClipsUtils();
    cleanupsUtils = new CleanupsUtils();
    partnersUtils = new PartnersUtils();
    episodeUtils = new EpisodeUtils();
    regexClip = clipsUtils.getDocumentWithoutSpecialCharactersInName();

    testClip = clipsUtils.getRandomDocument();
    LogUtils.logInfoMessage("Test ClipId set up before the suite: " + testClip.getId());
  }

  @Test
  @Description("Valid request - GetClipById")
  @TmsLink("28500618")
  public void C28500618_TEST() {
    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(testClip.getId()).getDocument(), Clips.class);

    Assert.assertEquals(testClip, mappedClip);
  }

  @Test
  @Description("GetByIds - transcode object")
  @TmsLink("28500698")
  public void C28500698_TEST() {
    Iterator clips = clipsUtils.getDocumentsWithTheField("transcode", true);
    Clips clipOne = (Clips) clips.next();
    Clips clipTwo = (Clips) clips.next();
    Clips clipThree = (Clips) clips.next();

    List<String> listIds = List.of(clipOne.getId(), clipTwo.getId(), clipThree.getId());

    List<Clip> listClips = clipsClient.getByIds(listIds).getDocumentsList();
    Assert.assertFalse(listClips.isEmpty());

    List<Clips> listMappedClips = clipsUtils.mapGrpcObjectsToPojo(listClips, Clips.class);
    List<Clips> listMongoDbClips = clipsUtils.getDocumentsByIds(listIds);

    listMappedClips.sort(Comparator.comparing(Clips::getId));
    listMongoDbClips.sort(Comparator.comparing(Clips::getId));

    Assert.assertEquals(listMappedClips, listMongoDbClips);
  }

  @Test
  @Description("GetByIds - with and without transcode objects")
  @TmsLink("28500697")
  public void C28500697_TEST() {
    Iterator clips = clipsUtils.getDocumentsWithTheField("transcode", true);
    Iterator clipsWithoutTranscode = clipsUtils.getDocumentsWithTheField("transcode", false);
    Clips clipOne = (Clips) clips.next();
    Clips clipTwo = (Clips) clipsWithoutTranscode.next();

    List<String> listIds = List.of(clipOne.getId(), clipTwo.getId());

    List<Clip> listClips = clipsClient.getByIds(listIds).getDocumentsList();
    Assert.assertFalse(listClips.isEmpty());

    List<Clips> listMappedClips = clipsUtils.mapGrpcObjectsToPojo(listClips, Clips.class);
    List<Clips> listMongoDbClips = clipsUtils.getDocumentsByIds(listIds);

    listMappedClips.sort(Comparator.comparing(Clips::getId));
    listMongoDbClips.sort(Comparator.comparing(Clips::getId));

    Assert.assertEquals(listMappedClips, listMongoDbClips);
  }

  @Test
  @Description("Create and GetById - transcode object")
  @TmsLink("28500699")
  public void C28500699_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();
    Clip clipsGrpcCreate = auth.create(clipGrpcToCreate).getDocument();
    Assert.assertNotNull(clipsGrpcCreate.getTranscode());
    Assert.assertNotNull(clipsGrpcCreate.getTranscode().getProfile());

    Clip clipGrpcById = clipsClient.getById(clipsGrpcCreate.getId()).getDocument();
    Clips clipsGrpcPojo = clipsUtils.mapGrpcObjectToPojo(clipGrpcById, Clips.class);
    Clips mongoDbClip = clipsUtils.getDocumentById(clipsGrpcCreate.getId());

    Assert.assertEquals(clipsGrpcPojo.getId(), mongoDbClip.getId());
    Assert.assertNotNull(clipsGrpcPojo.getTranscode());
    Assert.assertEquals(clipsGrpcPojo.getTranscode(), mongoDbClip.getTranscode());
    Assert.assertFalse(mongoDbClip.getTranscode().getState().isEmpty());
    Assert.assertFalse(mongoDbClip.getTranscode().getCode().isEmpty());
    Assert.assertFalse(mongoDbClip.getTranscode().getError().isEmpty());
    Assert.assertFalse(mongoDbClip.getTranscode().getJobId().isEmpty());
    Assert.assertNotNull(mongoDbClip.getTranscode().getUpdatedAt());
    Assert.assertNotNull(mongoDbClip.getTranscode().getProfile());
    Assert.assertEquals(clipsGrpcPojo, mongoDbClip);

    clipsClientAuth.deleteById(clipsGrpcPojo.getId());
  }

  @Test
  @Description("Create - episode and clip with highlight object")
  @TmsLink("28500700")
  public void C28500700_TEST() {
    EpisodesClient episodesClient = new EpisodesClient(grpcChannelManager.getChannel(), true);
    ClipsClient clipsClient = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipWithHighlight = clipsClient.getClipGrpcToCreate();
    Clip clipGrpcToCreate = clipWithHighlight.toBuilder().clearHighlight().build();

    Clip createdClip = clipsClient.create(clipGrpcToCreate).getDocument();
    String createdClipId = createdClip.getId();
    LogUtils.logInfoMessage("Created Clip ID: " + createdClipId);
    Assert.assertTrue(createdClip.getHighlight().toString().isEmpty());

    tv.pluto.ip.dal.episode.Episodes.Source source = clipsClient.getSource(createdClip.getId());

    tv.pluto.ip.dal.episode.Episodes.Episode createEpisode =
        episodesClient.getNewEpisodeBuild().toBuilder()
            .addAllSources(List.of(source))
            .setActiveRegion(clipWithHighlight.getActiveRegion())
            .build();

    tv.pluto.ip.dal.episode.Episodes.EpisodeCreate createdDocument =
        episodesClient.create(createEpisode).getDocument();
    String createdEpisodeId = createdDocument.getId();
    LogUtils.logInfoMessage("Created Episode ID: " + createdEpisodeId);

    tv.pluto.ip.dal.episode.Episodes.Episode createdEpisode =
        episodesClient.getEpisodeById(createdEpisodeId).getDocument();
    Assert.assertFalse(createdEpisode.getHighlight(), "created Episode has highlight = true");

    tv.pluto.ip.dal.clip.Clips.Highlight.Builder highlightBuild =
        clipsClient.getHighlightsClipBuilder(createdEpisodeId);

    Clip clipBuilder = Clip.newBuilder().setHighlight(highlightBuild).build();

    Clip updateClip =
        clipsClient
            .updateClipFields(createdClipId, clipBuilder, List.of("highlight"))
            .getDocument();

    Assert.assertEquals(
        updateClip.getHighlight().getOutputs(0).getId(), createdEpisodeId, "Clip wasn't updated");

    Episodes updatedEpisodes = episodeUtils.getDocumentById(createdEpisodeId);
    LogUtils.logInfoMessage("updatedEpisode id: " + updatedEpisodes.getId());
    LogUtils.logInfoMessage("updatedEpisodes.getHighlight(): " + updatedEpisodes.getHighlight());
    Assert.assertTrue(updatedEpisodes.getHighlight(), "updated Episode has highlight = false");

    clipsClient.deleteByIdWithAssertion(createdClipId);
    episodesClient.deleteEpisodeWithAssertion(createdEpisodeId);
  }

  @Test
  @Description("UpdateEpisode - episode and clip with highlight object")
  @TmsLink("28500701")
  public void C28500701_TEST() {
    EpisodesClient episodesClient = new EpisodesClient(grpcChannelManager.getChannel(), true);
    ClipsClient clipsClient = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipWithHighlight = clipsClient.getClipGrpcToCreate();
    Clip clipGrpcToCreate = clipWithHighlight.toBuilder().clearHighlight().build();

    // create clip
    Clip createdClip = clipsClient.create(clipGrpcToCreate).getDocument();
    String createdClipId = createdClip.getId();
    LogUtils.logInfoMessage("Created Clip ID: " + createdClipId);
    Assert.assertTrue(createdClip.getHighlight().toString().isEmpty());

    tv.pluto.ip.dal.episode.Episodes.Episode createEpisode =
        episodesClient.getNewEpisodeBuild().toBuilder()
            .setActiveRegion(clipWithHighlight.getActiveRegion())
            .build();

    // Create episode without a source
    String createdEpisodeId = episodesClient.create(createEpisode).getDocument().getId();
    LogUtils.logInfoMessage("Created Episode ID: " + createdEpisodeId);

    tv.pluto.ip.dal.episode.Episodes.Episode createdEpisode =
        episodesClient.getEpisodeById(createdEpisodeId).getDocument();
    Assert.assertFalse(createdEpisode.getHighlight(), "created Episode has highlight = true");

    tv.pluto.ip.dal.clip.Clips.Highlight.Builder highlightBuild =
        clipsClient.getHighlightsClipBuilder(createdEpisodeId);

    Clip clipBuilder = Clip.newBuilder().setHighlight(highlightBuild).build();

    // update clip with a highlight episode id
    Clip updateClip =
        clipsClient
            .updateClipFields(createdClipId, clipBuilder, List.of("highlight"))
            .getDocument();

    Assert.assertEquals(
        updateClip.getHighlight().getOutputs(0).getId(), createdEpisodeId, "Clip wasn't updated");

    Episodes updatedEpisodesWithoutSource = episodeUtils.getDocumentById(createdEpisodeId);
    Assert.assertFalse(
        updatedEpisodesWithoutSource.getHighlight(), "updated Episode has highlight = true");

    // updateSource in episodes
    tv.pluto.ip.dal.episode.Episodes.Source source = clipsClient.getSource(createdClip.getId());
    tv.pluto.ip.dal.episode.Episodes.Episode updateEpisode =
        createEpisode.toBuilder().addAllSources(List.of(source)).build();
    episodesClient.getUpdateFields(createdEpisodeId, List.of("sources"), updateEpisode);

    Episodes updatedEpisodeWithSource = episodeUtils.getDocumentById(createdEpisodeId);
    Assert.assertTrue(
        updatedEpisodeWithSource.getHighlight(), "updated Episode has highlight = false");

    clipsClient.deleteByIdWithAssertion(createdClipId);
    episodesClient.deleteEpisodeWithAssertion(createdEpisodeId);
  }

  @Test
  @Description("GetById - languageOverrides and regionOverrides")
  @TmsLink("28500690")
  public void C28500690_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    Clip clip = clipsClient.getById(clipsMongo.getId()).getDocument();
    Clips mappedClips = clipsUtils.mapGrpcObjectToPojo(clip, Clips.class);

    Assert.assertFalse(mappedClips.getLanguageOverrides().isEmpty());
    Assert.assertFalse(mappedClips.getRegionOverrides().isEmpty());
    Assert.assertEquals(clipsMongo, mappedClips);
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("GetByIds - languageOverrides and regionOverrides")
  @TmsLink("28500691")
  public void C28500691_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    List<Clip> listClip = clipsClient.getByIds(List.of(clipsMongo.getId())).getDocumentsList();
    Clips mappedClips = clipsUtils.mapGrpcObjectToPojo(listClip.get(0), Clips.class);

    Assert.assertFalse(mappedClips.getLanguageOverrides().isEmpty());
    Assert.assertFalse(mappedClips.getRegionOverrides().isEmpty());
    Assert.assertEquals(clipsMongo, mappedClips);
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("GetAllPaged - languageOverrides and regionOverrides")
  @TmsLink("28500692")
  public void C28500692_TEST() {
    int sortValue = 1;
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);

    Filter filter = clipsClient.getFilter("activeRegion", clipsMongo.getActiveRegion(), "string");

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

    GetAllPagedResponse clipsAllPaged =
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .getAllPaged(10, 0, grpcSort, List.of(filter), true);

    List<Clip> listClipsGrpc = clipsAllPaged.getDocumentsList();
    List<String> listClipIds =
        listClipsGrpc.stream().map(c -> c.getId()).collect(Collectors.toList());

    List<Clips> mongoClipsList = clipsUtils.getDocumentsByIds(listClipIds, 1);
    List<Clips> mappedClipsList = clipsUtils.mapGrpcObjectsToPojo(listClipsGrpc, Clips.class);

    Assert.assertFalse(mongoClipsList.get(0).getLanguageOverrides().isEmpty());
    Assert.assertFalse(mongoClipsList.get(0).getRegionOverrides().isEmpty());
    Assert.assertEquals(mongoClipsList, mappedClipsList);
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("GetAll - languageOverrides and regionOverrides")
  @TmsLink("28500693")
  public void C28500693_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    Iterator<Clip> iterator = clipsClient.getAll(clipsMongo.getActiveRegion());
    boolean isTrue = true;

    while (iterator.hasNext() && isTrue) {
      Clip clip = iterator.next();
      if (!clip.getLanguageOverridesMap().isEmpty()) {
        Clips mongoDbClip = clipsUtils.getDocumentById(clip.getId());
        Clips mappedClips = clipsUtils.mapGrpcObjectToPojo(clip, Clips.class);
        Assert.assertFalse(mappedClips.getLanguageOverrides().isEmpty());
        Assert.assertFalse(mappedClips.getRegionOverrides().isEmpty());
        Assert.assertEquals(mongoDbClip, mappedClips);
        isTrue = false;
      }
    }

    Assert.assertFalse(isTrue);
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("GetClipsByIds - languageOverrides and regionOverrides")
  @TmsLink("28500694")
  public void C28500694_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    List<Clip> clipsList = clipsClient.getClipsByIds(List.of(clipsMongo.getId())).getClipsList();
    Assert.assertFalse(clipsList.isEmpty());

    for (Clip clip : clipsList) {
      Clips mongoDbClip = clipsUtils.getDocumentById(clip.getId());
      Clips mappedClips = clipsUtils.mapGrpcObjectToPojo(clip, Clips.class);
      Assert.assertFalse(mappedClips.getLanguageOverrides().isEmpty());
      Assert.assertFalse(mappedClips.getRegionOverrides().isEmpty());
      Assert.assertEquals(mongoDbClip, mappedClips);
      auth.deleteById(clip.getId());
    }
  }

  @Test
  @Description("GetDocumentsUpdatedBetweenDates - languageOverrides and regionOverrides")
  @TmsLink("28500695")
  public void C28500695_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    String createdId = clipsMongo.getId();

    String updateName = new Faker().name().username();
    Clip document = auth.updateClipsName(clipsMongo.getId(), updateName).getDocument();
    Assert.assertEquals(document.getName(), updateName);

    LocalDateTime start = LocalDateTime.now(ZoneOffset.UTC).minusSeconds(10);
    LocalDateTime max = LocalDateTime.now(ZoneOffset.UTC).plusSeconds(30);

    ContentFeedQuery contentFeedQuery =
        ContentFeedQuery.builder().updatedAtMin(start).updatedAtMax(max).limit(0).build();

    List<Clips> mongoClips = clipsUtils.getDocumentsForContentFeeds(contentFeedQuery);

    Iterator<Clip> clips =
        clipsClient.getDocumentsUpdatedBetweenDates(
            start.toInstant(ZoneOffset.UTC).toString(), max.toInstant(ZoneOffset.UTC).toString());
    Clips responseClip = null;

    while (clips.hasNext()) {
      Clip next = clips.next();
      if (next.getId().equals(createdId)) {
        responseClip = clipsUtils.mapGrpcObjectToPojo(next, Clips.class);
        break;
      }
    }

    Assert.assertNotNull(responseClip);

    Clips mongoDbClip =
        mongoClips.stream().filter(c -> c.getId().equals(createdId)).findFirst().orElseThrow();

    LogUtils.logInfoMessage("MongoDbClip: " + mongoDbClip);

    Assert.assertFalse(mongoDbClip.getLanguageOverrides().isEmpty(), "LanguageOverrides is empty");
    Assert.assertFalse(mongoDbClip.getRegionOverrides().isEmpty(), "RegionOverrides is empty");
    Assert.assertEquals(mongoDbClip, responseClip, "MongoDbClip and responseClip are not equal");
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("cFeedsSyncDocuments - languageOverrides and regionOverrides")
  @TmsLink("28500696")
  public void C28500696_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clips clipsMongo = clipsUtils.createClip(auth);
    String updateName = new Faker().name().username();
    Clip document = auth.updateClipsName(clipsMongo.getId(), updateName).getDocument();
    Assert.assertEquals(document.getName(), updateName);
    Clips updatedDoc = clipsUtils.getDocumentById(document.getId());
    System.out.println(updatedDoc.getUpdatedAt());

    Instant time = updatedDoc.getUpdatedAt().toInstant(ZoneOffset.UTC);

    Iterator iteratorGrpcCFeedsSync =
        clipsClient.getCFeedsResponse(null, time.toString(), null, "cFeedsSyncDocuments");
    boolean received = false;

    while (iteratorGrpcCFeedsSync.hasNext()) {
      Clips clips = clipsUtils.mapGrpcObjectToPojo(iteratorGrpcCFeedsSync.next(), Clips.class);
      if (clips.getId().equals(clipsMongo.getId())) {
        Assert.assertFalse(clips.getLanguageOverrides().isEmpty());
        Assert.assertFalse(clips.getRegionOverrides().isEmpty());
        Assert.assertEquals(updatedDoc, clips);
        received = true;
        break;
      }
    }

    Assert.assertTrue(received);
    auth.deleteById(clipsMongo.getId());
  }

  @Test
  @Description("GetClipById - highlight object")
  @TmsLink("28500619")
  public void C28500619_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();

    Clip createdClip = auth.create(clipGrpcToCreate).getDocument();
    Assert.assertNotNull(createdClip.getTranscode());

    String createdId = createdClip.getId();
    Clips mongoClip = clipsUtils.getDocumentById(createdId);

    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            new ClipsClient(grpcChannelManager.getChannel(), false)
                .getById(createdId)
                .getDocument(),
            Clips.class);

    LogUtils.logInfoMessage("Test id for C30614402_TEST: " + createdId);
    Assert.assertFalse(mappedClip.getHighlight().getOutputs().isEmpty());
    Assert.assertNotNull(mappedClip.getHighlight().getOutputs().get(0).getId());
    Assert.assertNotNull(mappedClip.getHighlight().getOutputs().get(0).getMedias());
    Assert.assertNotNull(mongoClip.getHighlight().getOutputs().get(0).getMedias());

    Assert.assertEquals(mongoClip, mappedClip);
    Assert.assertEquals(
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .deleteById(createdId)
            .getDeletedCount(),
        1);
  }

  @Test
  @Description("GetClipById - update highlight without markupId")
  @TmsLink("28500711")
  public void C28500711_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();

    tv.pluto.ip.dal.clip.Clips.Highlight highlight =
        clipGrpcToCreate.getHighlight().toBuilder()
            .clearOutputs()
            .addOutputs(clipGrpcToCreate.getHighlight().getOutputs(0).toBuilder().clearMarkupId())
            .build();

    Clip clipGrpcToCreateNoMarkUpId =
        clipGrpcToCreate.toBuilder().clearHighlight().setHighlight(highlight).build();

    Clip createdClip = auth.create(clipGrpcToCreateNoMarkUpId).getDocument();
    Assert.assertNotNull(createdClip.getTranscode());

    String markUpId = createdClip.getMarkupsList().get(0).getId();

    tv.pluto.ip.dal.clip.Clips.HighlightOutput.Builder highlightOutputBuilder =
        createdClip.getHighlight().getOutputs(0).toBuilder().setMarkupId(markUpId);

    // Update Highlight builder with modified HighlightOutput
    tv.pluto.ip.dal.clip.Clips.Highlight.Builder highlightBuilderWithMarkupId =
        createdClip.getHighlight().toBuilder().clearOutputs().addOutputs(highlightOutputBuilder);

    Clip updatedClipMarkupId =
        createdClip.toBuilder().setHighlight(highlightBuilderWithMarkupId).build();

    Clip updatedClip =
        auth.updateClipFields(createdClip.getId(), updatedClipMarkupId, List.of("highlight"))
            .getDocument();

    String createdId = updatedClip.getId();
    Clips mongoClip = clipsUtils.getDocumentById(createdId);
    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            new ClipsClient(grpcChannelManager.getChannel(), false)
                .getById(createdId)
                .getDocument(),
            Clips.class);

    Assert.assertFalse(mappedClip.getHighlight().getOutputs().isEmpty());

    Cleanup cleanup = cleanupsUtils.getDocumentByKeyValue("data.markupId", markUpId);
    Assert.assertNull(cleanup);

    Assert.assertEquals(mongoClip, mappedClip);
    Assert.assertEquals(
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .deleteById(createdId)
            .getDeletedCount(),
        1);
  }

  @Test
  @Description("GetClipById - update highlight start with markupId")
  @TmsLink("28500712")
  public void C28500712_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();

    Clip createdClip = auth.create(clipGrpcToCreate).getDocument();
    Assert.assertNotNull(createdClip.getMarkupsList());

    String markUpId = createdClip.getMarkupsList().get(0).getId();

    tv.pluto.ip.dal.clip.Clips.HighlightOutput buildOutput =
        tv.pluto.ip.dal.clip.Clips.HighlightOutput.newBuilder()
            .setMarkupId(markUpId)
            .setStartOffsetMs(0)
            .setEndOffsetMs(3000)
            .build();

    tv.pluto.ip.dal.clip.Clips.Highlight highlightOutputBuilder =
        createdClip.getHighlight().toBuilder().addOutputs(buildOutput).build();

    Clip updatedClipStart = createdClip.toBuilder().setHighlight(highlightOutputBuilder).build();
    System.out.println("Test id for TEST: " + createdClip.getId());

    Clip updatedClip =
        auth.updateClipFields(createdClip.getId(), updatedClipStart, List.of("highlight"))
            .getDocument();

    String createdId = updatedClip.getId();
    Clips mongoClip = clipsUtils.getDocumentById(createdId);

    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            new ClipsClient(grpcChannelManager.getChannel(), false)
                .getById(createdId)
                .getDocument(),
            Clips.class);

    Assert.assertFalse(mappedClip.getHighlight().getOutputs().isEmpty());

    List<Cleanup> listCleanup = cleanupsUtils.getDocumentsByKeyValue("data.markupId", markUpId);
    Assert.assertFalse(listCleanup.isEmpty(), "Cleanup document not found");

    boolean dateBetweenDates =
        CommonUtils.isDateBetweenDates(
            Instant.now().minusSeconds(60),
            Instant.now().plusSeconds(10),
            listCleanup.get(0).getCreatedAt().toInstant());
    Assert.assertTrue(dateBetweenDates);

    Assert.assertEquals(mongoClip, mappedClip);
    Assert.assertEquals(
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .deleteById(createdId)
            .getDeletedCount(),
        1);
  }

  @Test
  @Description("GetClipById - update highlight without markups")
  @TmsLink("28500713")
  public void C28500713_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();
    String markUpId = clipGrpcToCreate.getHighlight().getOutputs(0).getMarkupId();

    Clip clipNoMarkUps = clipGrpcToCreate.toBuilder().clearMarkups().clearHighlight().build();

    Clip createdClip = auth.create(clipNoMarkUps).getDocument();
    Assert.assertNotNull(createdClip.getTranscode());

    Cleanup cleanupBefore = cleanupsUtils.getDocumentByKeyValue("data.markupId", markUpId);
    Assert.assertNull(cleanupBefore);

    Clip updatedClip =
        auth.updateClipFields(createdClip.getId(), clipGrpcToCreate, List.of("highlight"))
            .getDocument();

    String createdId = updatedClip.getId();
    Clips mongoClip = clipsUtils.getDocumentById(createdId);
    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            new ClipsClient(grpcChannelManager.getChannel(), false)
                .getById(createdId)
                .getDocument(),
            Clips.class);

    Assert.assertTrue(mappedClip.getHighlight().getOutputs().isEmpty());
    Assert.assertTrue(mappedClip.getMarkups().isEmpty());

    Cleanup cleanupAfter = cleanupsUtils.getDocumentByKeyValue("data.markupId", markUpId);
    Assert.assertNotNull(cleanupAfter);
    Assert.assertEquals(
        cleanupAfter.getData().getStartOffsetMs(),
        clipGrpcToCreate.getHighlight().getOutputs(0).getStartOffsetMs());
    Assert.assertEquals(
        cleanupAfter.getData().getEndOffsetMs(),
        clipGrpcToCreate.getHighlight().getOutputs(0).getEndOffsetMs());

    boolean dateBetweenDates =
        CommonUtils.isDateBetweenDates(
            Instant.now().minusSeconds(60),
            Instant.now().plusSeconds(10),
            cleanupAfter.getCreatedAt().toInstant());

    Assert.assertTrue(dateBetweenDates);

    Assert.assertEquals(mongoClip, mappedClip);
    Assert.assertEquals(
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .deleteById(createdId)
            .getDeletedCount(),
        1);
    cleanupsUtils.deleteDocumentById(cleanupAfter.getId());
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Clip document for requested ID not found")
  @Description("Invalid request - GetClipById")
  @TmsLink("28500620")
  public void C28500620_TEST() {
    clipsClient.getById(INVALID_ID_VALUE);
  }

  @Test
  @Description("Valid request with single clip - GetClipsByIds")
  @TmsLink("28500621")
  public void C28500621_TEST() {
    List<String> randomClipsIds = Collections.singletonList(testClip.getId());

    List<Clips> mongoClipsList = clipsUtils.getDocumentsByIds(randomClipsIds);
    List<?> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getByIds(randomClipsIds).getDocumentsList(), Clips.class);

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test
  @Description("Valid request with multiple clips - GetClipsByIds")
  @TmsLink("28500622")
  public void C28500622_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();

    List<Clips> allMongoClipsList = clipsUtils.getDocumentsByIds(randomClipsIds);
    List<Clips> mongoClipsList =
        allMongoClipsList.stream().filter(c -> !c.getIsArchived()).collect(Collectors.toList());

    List<?> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getByIds(randomClipsIds).getDocumentsList(), Clips.class);

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Clip documents for requested IDs not found")
  @Description("Invalid request with single clip - GetClipsByIds")
  @TmsLink("28500623")
  public void C28500623_TEST() {
    List<String> randomClipsIds = Collections.singletonList(INVALID_ID_VALUE);
    clipsClient.getByIds(randomClipsIds);
  }

  @Test
  @Description("Valid request with invalid clip - GetClipsByIds")
  @TmsLink("28500624")
  public void C28500624_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();
    randomClipsIds.add(INVALID_ID_VALUE);

    List<Clips> allMongoClipsList = clipsUtils.getDocumentsByIds(randomClipsIds);
    List<Clips> mongoClipsList =
        allMongoClipsList.stream().filter(c -> !c.getIsArchived()).collect(Collectors.toList());
    List<?> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getByIds(randomClipsIds).getDocumentsList(), Clips.class);

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test
  @Description("GetDocumentsUpdatedBetweenDates - Time period for which there is a clip")
  @TmsLink("28500649")
  public void C28500649_TEST() {

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

    List<Clips> mongoClips = clipsUtils.getDocumentsForContentFeeds(contentFeedQuery);

    List<Clips> grpcClips = new ArrayList<>();

    Iterator<Clip> clips =
        clipsClient.getDocumentsUpdatedBetweenDates(
            clipsUtils.updatedAtMinString, clipsUtils.updatedAtMaxString);

    while (clips.hasNext()) {
      grpcClips.add(clipsUtils.mapGrpcObjectToPojo(clips.next(), Clips.class));
    }

    mongoClips.sort(Comparator.comparing(Clips::getId));
    grpcClips.sort(Comparator.comparing(Clips::getId));

    List<String> mongoIds = mongoClips.stream().map(Clips::getId).toList();
    List<String> grpcIds = grpcClips.stream().map(Clips::getId).toList();

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

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("GetDocumentsUpdatedBetweenDates - Time period without channel")
  @TmsLink("28500650")
  public void C28500650_TEST() {
    clipsClient.getDocumentsUpdatedBetweenDates(failStartDateTime, failEndDateTime).next();
  }

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

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

  @Test(priority = -1)
  @Description("Valid request: updateByIdReturnUpdated - update summary")
  @TmsLink("28500626")
  public void C28500626_TEST() {
    String summary = new Faker().chuckNorris().fact();

    Clip grpcClip = Clip.newBuilder().setSummary(summary).build();

    List<String> updateFields = Collections.singletonList("summary");

    clipsClient.updateByIdReturnUpdated(CLIP_ID_FOR_UPDATE, grpcClip, updateFields);

    Clips updatedClip = clipsUtils.getDocumentById(CLIP_ID_FOR_UPDATE);

    Assert.assertEquals(updatedClip.getSummary(), summary);
  }

  @Test(priority = -1)
  @Description("Valid request: updateByIdReturnUpdated - update multiple fields")
  @TmsLink("28500627")
  public void C28500627_TEST() {
    String summary = new Faker().chuckNorris().fact();
    String copyright = new Faker().chuckNorris().fact();
    String updatedAt = LocalDateTime.now(ZoneOffset.UTC).format(DATE_TIME_FORMAT);

    Clip grpcClip =
        Clip.newBuilder()
            .setSummary(summary)
            .setCopyright(copyright)
            .setUpdatedAt(updatedAt)
            .build();

    List<String> updateFields = Arrays.asList("summary", "copyright", "updatedAt");

    clipsClient.updateByIdReturnUpdated(CLIP_ID_FOR_UPDATE, grpcClip, updateFields);

    Clips updatedClip = clipsUtils.getDocumentById(CLIP_ID_FOR_UPDATE);

    Assert.assertEquals(updatedClip.getSummary(), summary);
    Assert.assertEquals(updatedClip.getCopyright(), copyright);
    Assert.assertEquals(
        LocalDateTime.parse(updatedClip.getUpdatedAt().toString(), DATE_TIME_FORMATTER_RESPONSE),
        LocalDateTime.parse(updatedAt, DATE_TIME_FORMAT));
  }

  @Test(priority = -1)
  @Description("Valid request: updateByIdReturnUpdated - update array element")
  @TmsLink("28500681")
  public void C28500681_TEST() {
    Clips clipMongo = clipsUtils.getClipsSourcesTypeAndField("liveUrl", "liveBroadcast", true);
    Assert.assertNotNull(clipMongo);

    String url = new Faker().internet().url();
    Source source = Source.newBuilder().setFile(url).build();
    Clip grpcClip = Clip.newBuilder().addAllSources(Collections.singletonList(source)).build();

    List<String> updateFields = Collections.singletonList("sources");

    clipsClient.updateByIdReturnUpdated(clipMongo.getId(), grpcClip, updateFields);
    Clips updatedClip = clipsUtils.getDocumentById(clipMongo.getId());

    Assert.assertEquals(updatedClip.getSources().get(0).getFile(), url);
  }

  @Test
  @Description("Valid request - GetBackfillClips")
  @TmsLink("28500631")
  public void C28500631_TEST() {
    List<IdUpdated> mongoBackfillClips = clipsUtils.getBackfillClips();
    List<IdUpdated> grpcBackfillClips;

    // If no clips were found check exception message
    if (mongoBackfillClips.isEmpty()) {
      try {
        clipsClient.getBackfillClipsResponse();
      } catch (StatusRuntimeException ex) {
        Assert.assertEquals(ex.getMessage(), "NOT_FOUND: Clip backfill documents not found");
      }
    } else {
      grpcBackfillClips =
          clipsUtils.mapGrpcObjectsToPojo(
              clipsClient.getBackfillClipsResponse().getBackfillClipsList(), IdUpdated.class);

      mongoBackfillClips.sort(Comparator.comparing(IdUpdated::getId));
      grpcBackfillClips.sort(Comparator.comparing(IdUpdated::getId));

      Assert.assertEquals(mongoBackfillClips, grpcBackfillClips);
    }
  }

  @Test
  @Description("GetErrorClips - valid request")
  @TmsLink("28500632")
  public void C28500632_TEST() {
    List<IdUpdated> mongoErrorClips = clipsUtils.getErrorClips();
    List<IdUpdated> grpcErrorClips;

    // If no clips were found check exception message
    if (mongoErrorClips.isEmpty()) {
      try {
        clipsClient.getErrorClips();
      } catch (StatusRuntimeException ex) {
        Assert.assertEquals(ex.getMessage(), "NOT_FOUND: Clip backfill documents not found");
      }
    } else {
      grpcErrorClips =
          clipsUtils.mapGrpcObjectsToPojo(
              clipsClient.getErrorClips().getErrorClipsList(), IdUpdated.class);

      mongoErrorClips.sort(Comparator.comparing(IdUpdated::getId));
      grpcErrorClips.sort(Comparator.comparing(IdUpdated::getId));

      Assert.assertEquals(mongoErrorClips, grpcErrorClips);
    }
  }

  @Test(enabled = false) // TODO performance improvement required
  @Description("GetDataForAvailableVodContentRecommendations - valid request")
  @TmsLink("28500642")
  public void C28500642_TEST() {
    Iterator<Recommendation.StreamDataForAvailableVodContentRecommendationsResponse>
        grpcRecommendations = recommendationClient.getDataForAvailableVodContentRecommendations();

    int count = 0;
    while (grpcRecommendations.hasNext()) {
      count++;
      grpcRecommendations.next();
    }

    Assert.assertEquals(clipsUtils.getDataForAvailableVodContentRecommendations().size(), count);
  }

  @Test(priority = -1)
  @Description("UpdateContentMamUniqueIdsByIds - clips with contentUUID")
  @TmsLink("28500643")
  public void C28500643_TEST() {
    List<Clips> mongoClips =
        clipsUtils.getClipsWithUUID(5).stream()
            .filter(c -> !c.getId().equals(testClip.getId()))
            .collect(Collectors.toList());
    List<ObjectIdContentIdSet> objectIdContentIdSets = clipsUtils.extractIdsAndUUID(mongoClips);

    clipsClient.updateContentMamUniqueIdsByIds(objectIdContentIdSets);

    Map<String, String> contentMap = clipsUtils.getIdsFromContentSet(objectIdContentIdSets);

    SoftAssert softAssert = new SoftAssert();

    contentMap.forEach(
        (id, contentUUID) -> {
          Clips updatedClip = clipsUtils.getDocumentById(id);
          softAssert.assertEquals(updatedClip.getContentUUID(), contentUUID);
        });

    softAssert.assertAll();
  }

  @Test(priority = -1)
  @Description("UpdateContentMamUniqueIdsByIds - clips without contentUUID")
  @TmsLink("28500644")
  public void C28500644_TEST() {
    List<Clips> mongoClips =
        clipsUtils.getClipsWithUUID(3).stream()
            .filter(c -> !c.getId().equals(testClip.getId()))
            .collect(Collectors.toList());
    List<ObjectIdContentIdSet> objectIdContentIdSets = clipsUtils.extractIdsAndUUID(mongoClips);

    clipsClient.updateContentMamUniqueIdsByIds(objectIdContentIdSets);

    Map<String, String> contentMap = clipsUtils.getIdsFromContentSet(objectIdContentIdSets);

    SoftAssert softAssert = new SoftAssert();

    contentMap.forEach(
        (id, contentUUID) -> {
          Clips updatedClip = clipsUtils.getDocumentById(id);
          softAssert.assertEquals(updatedClip.getContentUUID(), contentUUID);
        });

    softAssert.assertAll();
  }

  @Test(priority = -1)
  @Issues({@Issue("ARCH-2359"), @Issue("ARCH-2360")})
  @Description("Create - creating new clip")
  @TmsLink("28500661")
  public void C28500661_TEST() {
    List<String> ids = clipsUtils.getRandomClipsIds();
    Faker faker = new Faker();

    ids.forEach(
        id -> {
          tv.pluto.ip.dal.clip.Clips.Clip initClip =
              new ClipsClient(grpcChannelManager.getChannel(), true).getById(id).getDocument();
          String name = initClip.getName();
          String contentUUID = initClip.getContentUUID();
          String replacedName = "DAL Create test clip";

          String json;
          Clip clip;
          try {
            json =
                ProtoJsonUtil.toJson(initClip)
                    .replace("\"name\": \"" + name + "\"", "\"name\": \"" + replacedName + "\"")
                    .replace("\"id\": \"" + id + "\",", "")
                    .replace(
                        "\"contentUUID\": \"" + contentUUID + "\"",
                        "\"contentUUID\": \"" + faker.internet().uuid() + "\"");

            clip = ProtoJsonUtil.fromJson(json, Clip.class);
          } catch (IOException e) {
            throw new RuntimeException(e);
          }

          tv.pluto.ip.dal.clip.Clips.CreateResponse createResponse = clipsClientAuth.create(clip);

          createdClipId = createResponse.getDocument().getId();

          createdClipsIds.add(createdClipId);
          LogUtils.logInfoMessage("C6629798_TEST Created clip ID = " + createdClipId);

          Clips grpcClip =
              clipsUtils.mapGrpcObjectToPojo(createResponse.getDocument(), Clips.class);

          Clips mongoClip = clipsUtils.getDocumentById(id);
          mongoClip.setId(createdClipId);
          mongoClip.setName(replacedName);
          if (mongoClip.getCaptioned().equals("")) { // //////
            mongoClip.setCaptioned("no");
          }
          mongoClip.setCreatedAt(grpcClip.getCreatedAt());
          mongoClip.setAuthor(grpcClip.getAuthor()); // ////////

          // TODO uncomment after issues with fields will be resolved
          //            Assert.assertEquals(mongoClip, grpcClip);
        });
  }

  @Test(priority = -1)
  @Description("Create - creating clip without authentication")
  @TmsLink("28500662")
  public void C28500662_TEST() {
    try {
      clipsClient.create(tv.pluto.ip.dal.clip.Clips.Clip.newBuilder().build());
    } catch (StatusRuntimeException e) {
      Assert.assertEquals(e.getStatus().getCode().value(), 16);
      Assert.assertEquals(
          e.getMessage(), "UNAUTHENTICATED: DB writes not allowed without authentication");
    }
  }

  @Test(
      priority = -1,
      dependsOnMethods = {"C28500661_TEST"})
  @Description("DeleteById - delete existing clip")
  @TmsLink("28500663")
  public void C28500663_TEST() {
    String clipId = clipsUtils.getRandomItem(createdClipsIds);
    createdClipsIds.remove(clipId);

    LogUtils.logInfoMessage("C6632908_TEST delete clips with IDs = " + clipId);
    Assert.assertEquals(clipsClientAuth.deleteById(clipId).getDeletedCount(), 1);
    Assert.assertNull(clipsUtils.getDocumentById(clipId));
  }

  @Test(priority = -1)
  @Description("DeleteById - delete non existing clip")
  @TmsLink("28500664")
  public void C28500664_TEST() {
    try {
      clipsClientAuth.deleteById(INVALID_ID_VALUE);
    } catch (StatusRuntimeException e) {
      Assert.assertEquals(e.getStatus().getCode().value(), 5);
      Assert.assertEquals(e.getMessage(), "NOT_FOUND: Clip documents for requested IDs not found");
    }
  }

  @Test(
      priority = -1,
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "UNAUTHENTICATED: DB deletes not allowed without authentication")
  @Description("DeleteById - delete clip without authentication")
  @TmsLink("28500665")
  public void C28500665_TEST() {
    clipsClient.deleteById(testClip.getId());
  }

  @Test(
      priority = -1,
      dependsOnMethods = {"C28500661_TEST", "C28500663_TEST"})
  @Description("DeleteByIds - delete a single clip")
  @TmsLink("28500666")
  public void C28500666_TEST() {
    String clipId = clipsUtils.getRandomItem(createdClipsIds);
    createdClipsIds.remove(clipId);

    List<String> ids = Collections.singletonList(clipId);
    int size = ids.size();

    LogUtils.logInfoMessage("C6632910_TEST delete clips with IDs = " + ids);
    Assert.assertEquals(clipsClientAuth.deleteByIds(ids).getDeletedCount(), size);
    Assert.assertTrue(clipsUtils.getDocumentsByIds(ids).isEmpty());
  }

  @Test(
      priority = -1,
      dependsOnMethods = {"C28500661_TEST", "C28500663_TEST", "C28500666_TEST"})
  @Description("DeleteByIds - delete multiple clips")
  @TmsLink("28500667")
  public void C28500667_TEST() {
    List<String> ids = createdClipsIds.stream().skip(2).collect(Collectors.toList());

    createdClipsIds =
        createdClipsIds.stream().filter(id -> !ids.contains(id)).collect(Collectors.toList());

    int size = ids.size();

    LogUtils.logInfoMessage("C6632911_TEST delete clips with IDs = " + ids);
    Assert.assertEquals(clipsClientAuth.deleteByIds(ids).getDeletedCount(), size);
    Assert.assertTrue(clipsUtils.getDocumentsByIds(ids).isEmpty());
  }

  @Test(priority = -1)
  @Description("DeleteByIds - delete non existing clip")
  @TmsLink("28500668")
  public void C28500668_TEST() {
    try {
      clipsClientAuth.deleteByIds(Collections.singletonList(INVALID_ID_VALUE));
    } catch (StatusRuntimeException e) {
      Assert.assertEquals(e.getStatus().getCode().value(), 5);
      Assert.assertEquals(e.getMessage(), "NOT_FOUND: Clip documents for requested IDs not found");
    }
  }

  @Test(
      priority = -1,
      dependsOnMethods = {"C28500661_TEST", "C28500663_TEST", "C28500663_TEST", "C28500667_TEST"})
  @Description("DeleteByIds - delete non existing clip")
  @TmsLink("28500669")
  public void C28500669_TEST() {
    int size = createdClipsIds.size();
    createdClipsIds.add(INVALID_ID_VALUE);

    LogUtils.logInfoMessage("C28500669_TEST delete clips with IDs = " + createdClipsIds);
    Assert.assertEquals(clipsClientAuth.deleteByIds(createdClipsIds).getDeletedCount(), size);
    Assert.assertTrue(clipsUtils.getDocumentsByIds(createdClipsIds).isEmpty());
  }

  @Test
  @Description("GetAll - Verify filter is returning correct data")
  @TmsLink("28500670")
  public void C28500670_TEST() {
    int limit = 10;
    String activeRegionFromEpisodes = episodeUtils.getSetActiveRegionFromEpisodes().get(0);
    Iterator<Clip> clipIterator = clipsClient.getAll(activeRegionFromEpisodes);
    List<Clip> listClip = clipsClient.listFromIteratorLimit(clipIterator, limit);
    Assert.assertEquals(limit, listClip.size());

    List<Clips> listClips = new ArrayList<>();
    List<Clips> listMongoClip = new ArrayList<>();

    listClip.forEach(
        clip -> {
          Clips clips = clipsUtils.mapGrpcObjectToPojo(clip, Clips.class);
          listClips.add(clips);

          Clips clipsMongoDb = clipsUtils.getDocumentById(clips.getId());
          Assert.assertEquals(
              activeRegionFromEpisodes,
              clipsMongoDb.getActiveRegion(),
              "Active region is not expected");
          listMongoClip.add(clipsMongoDb);
        });

    listClips.sort(Comparator.comparing(Clips::getId));
    listMongoClip.sort(Comparator.comparing(Clips::getId));

    Assert.assertEquals(
        listClips, listMongoClip, "List Clips from gRPC and Mongo DB are not equal");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Not found")
  @Description(
      "GetAll - Verify filter is not returning anything if the active region does not exist")
  @TmsLink("28500171")
  public void C28500171_TEST() {
    clipsClient.getAll("justTest").next();
  }

  @Test()
  @Description(
      "Dash enabled updates from false to true if all clips have dash and promotional field is false")
  @TmsLink("28500671")
  public void C28500671_TEST() {
    Episodes episode = episodeUtils.dashEnabledFromEpisode(1, false);

    Episodes mongoEpisodeBefore = episodeUtils.getDocumentById(episode.getId());
    Assert.assertFalse(mongoEpisodeBefore.getDashEnabled());

    String clipId = mongoEpisodeBefore.getSources().get(0).getClip();
    clipsClient.updateClipsName(clipId, "dalTestField");

    Episodes mongoEpisode = episodeUtils.getDocumentById(episode.getId());
    Assert.assertTrue(mongoEpisode.getDashEnabled());
  }

  @Test
  @Description("UpdateFields for HLS clips")
  @TmsLink("28500679")
  public void C28500679_TEST() {
    LocalDateTime localDateTimeBeforeTest = CommonUtils.getNowDateTimeUtc();
    Clip clipBuilder = clipsClient.getClipGrpcToCreate();
    Clip createdClip =
        new ClipsClient(grpcChannelManager.getChannel(), true).create(clipBuilder).getDocument();
    String createdId = createdClip.getId();

    Clips mongoClip = clipsUtils.getDocumentById(createdId);
    clipsClient.updateClipsName(mongoClip.getId(), "dalTest");
    Clips mongoClipAfterUpdate = clipsUtils.getDocumentById(mongoClip.getId());

    Assert.assertTrue(localDateTimeBeforeTest.isBefore(mongoClipAfterUpdate.getUpdatedAt()));
    Assert.assertTrue(
        CommonUtils.getNowDateTimeUtc()
            .plusSeconds(1)
            .isAfter(mongoClipAfterUpdate.getUpdatedAt()));
  }

  @Test
  @Description("UpdateFields - markups")
  @TmsLink("28500680")
  public void C28500680_TEST() {
    Clips clips = clipsUtils.getExistsAndSizeNotZero("markups");
    Clip clipGrpc = clipsClient.getById(clips.getId()).getDocument();
    tv.pluto.ip.dal.clip.Clips.Markup markupsGetById = clipGrpc.getMarkups(0);

    int updatedStart = markupsGetById.getStart() + 1;
    int updatedEnd = markupsGetById.getEnd() + 1;

    tv.pluto.ip.dal.clip.Clips.Markup markup =
        Clip.newBuilder()
            .addMarkupsBuilder()
            .setId(markupsGetById.getId())
            .setObjectId(markupsGetById.getObjectId())
            .setType(markupsGetById.getType())
            .setStart(updatedStart)
            .setEnd(updatedEnd)
            .build();

    Clip clipBuild = Clip.newBuilder().addAllMarkups(List.of(markup)).build();
    LogUtils.logInfoMessage("Clip builder " + clipBuild);

    Clip updateClip =
        clipsClient
            .updateByIdReturnUpdated(clips.getId(), clipBuild, List.of("markups"))
            .getDocument();

    Assert.assertEquals(1, updateClip.getMarkupsCount());
    tv.pluto.ip.dal.clip.Clips.Markup updatedMarkUp = updateClip.getMarkups(0);

    Assert.assertEquals(updatedMarkUp.getId(), markup.getId());
    Assert.assertEquals(updatedMarkUp.getObjectId(), markup.getObjectId());
    Assert.assertEquals(updatedMarkUp.getStart(), markup.getStart());
    Assert.assertEquals(updatedMarkUp.getEnd(), markup.getEnd());

    tv.pluto.ip.dal.clip.Clips.Markup updatedMarkupId =
        clipsClient.getById(clips.getId()).getDocument().getMarkupsList().get(0);
    Assert.assertEquals(updatedMarkupId.getId(), markup.getId());
    Assert.assertEquals(updatedMarkupId.getObjectId(), markup.getObjectId());
    Assert.assertEquals(updatedMarkupId.getStart(), markup.getStart());
    Assert.assertEquals(updatedMarkupId.getEnd(), markup.getEnd());
  }

  @Test
  @Description("Dash enabled no updates when promotional field is true")
  @TmsLink("28500672")
  public void C28500672_TEST() {
    Episodes episode = episodeUtils.dashEnabledFromEpisode(1, true);

    Episodes mongoEpisodeBefore = episodeUtils.getDocumentById(episode.getId());
    Assert.assertFalse(mongoEpisodeBefore.getDashEnabled());

    String clipId = mongoEpisodeBefore.getSources().get(0).getClip();
    clipsClient.updateClipsName(clipId, "dalTestField");

    Episodes mongoEpisode = episodeUtils.getDocumentById(episode.getId());
    Assert.assertFalse(mongoEpisode.getDashEnabled());
  }

  @Test
  @Description("Clip sources are returning adSparxAdPolicy field")
  @TmsLink("28500673")
  public void C28500673_TEST() {
    String adSparxAdPolicy = "adSparxAdPolicy";
    Clips clip = clipsUtils.getClipsIdWithFieldInSources(adSparxAdPolicy);
    Clips mappedClip =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(clip.getId()).getDocument(), Clips.class);

    Assert.assertEquals(clip, mappedClip);
    Assert.assertTrue(
        mappedClip.getSources().stream().anyMatch(source -> source.getAdSparxAdPolicy() != null));
  }

  @Test
  @Description("CFeedsSyncAllIds - get CFEEDs ids")
  @TmsLink("28500676")
  public void C28500676_TEST() {
    Iterator<tv.pluto.ip.dal.clip.Clips.Id> clipsIdsFromCFeeds =
        clipsClient.getClipsIdsFromCFeeds(true);
    for (int i = 0; i < 100; i++) {
      String grpcId = clipsIdsFromCFeeds.next().getId();
      boolean mongoPublished = ((Clips) clipsUtils.getDocumentById(grpcId)).getPublished();
      Assert.assertTrue(mongoPublished);
    }
  }

  @Test
  @Description("cFeedsSyncDocuments - last_run_at")
  @TmsLink("28500677")
  public void C28500677_TEST() {
    LocalDateTime time = LocalDateTime.now(ZoneOffset.UTC).minusWeeks(1);
    Iterator iteratorGrpcCFeedsSync =
        clipsClient.getCFeedsResponse(null, time + "Z", null, "cFeedsSyncDocuments");

    int total = 0;
    Clip clip = null;

    while (iteratorGrpcCFeedsSync.hasNext() && total < 50) {
      try {
        clip = (Clip) iteratorGrpcCFeedsSync.next();
        Clips clips = clipsUtils.mapGrpcObjectToPojo(clip, Clips.class);
        Assert.assertTrue(clips.getUpdatedAt().isAfter(time) || clips.getUpdatedAt().equals(time));
        total++;
      } catch (NumberFormatException e) {
        assert clip != null;
        Assert.assertNotNull(clip.getId());
        LogUtils.logInfoMessage("Failed to parse date. Clip id: " + clip.getId());
        Assert.assertTrue(e.getMessage().contains("Failed to parse date"));
      }
    }
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND_MESSAGE)
  @Description("cFeedsSyncDocuments - last_run_at future time")
  @TmsLink("28500678")
  public void C28500678_TEST() {
    String futureTime = CommonUtils.localDateTimeStringPlusDays(555);
    clipsClient.getCFeedsResponse(null, futureTime, null, "cFeedsSyncDocuments").next();
  }

  @Test
  @Description("Verify a new field discrete_audio is populated in Clips")
  @TmsLink("28500682")
  public void C28500682_TEST() {
    ClipsClient auth = new ClipsClient(grpcChannelManager.getChannel(), true);
    Clip clipGrpcToCreate = clipsClient.getClipGrpcToCreate();
    Clip clipResponse = auth.create(clipGrpcToCreate).getDocument();
    Clips clipsGrpc = clipsUtils.mapGrpcObjectToPojo(clipResponse, Clips.class);

    Assert.assertFalse(clipsGrpc.getDiscreteAudio().isEmpty());

    clipsGrpc
        .getDiscreteAudio()
        .forEach(
            discreteAudio -> {
              Assert.assertNotNull(discreteAudio.getAudioType());
              Assert.assertNotNull(discreteAudio.getLanguage());
              Assert.assertNotNull(discreteAudio.getUri());
            });

    Assert.assertEquals(
        1,
        new ClipsClient(grpcChannelManager.getChannel(), true)
            .deleteById(clipResponse.getId())
            .getDeletedCount());
  }

  @Test
  @Description("Clip URI field")
  @TmsLink("28500683")
  public void C28500683_TEST() {
    Clips mongoClips = clipsUtils.getRandomDocumentWithTheField("timedText.uri", true);
    long timedTextUriExist =
        mongoClips.getTimedText().stream()
            .filter(timedText -> !timedText.getUri().isEmpty())
            .count();
    Clips grpcClips =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(mongoClips.getId()).getDocument(), Clips.class);

    Assert.assertFalse(grpcClips.getTimedText().get(0).getUri().isEmpty());
    Assert.assertTrue(timedTextUriExist > 0);
    Assert.assertEquals(grpcClips, mongoClips);
  }

  @Test
  @Description("GetComScoreById - has Metadata and StreamingTag objects")
  @TmsLink("28500684")
  public void C28500684_TEST() throws IOException {
    String stringComScore =
        Files.readString(Paths.get("src/main/resources/schema/comScoreById.json"));
    Partners mongoPartner = partnersUtils.getRandomDocumentWithTheField("comScore.c2", true);
    Clips clips = clipsUtils.getDocumentByFieldAndId("partner", mongoPartner.getId());
    LogUtils.logInfoMessage("Clip id with comScore: " + clips.getId());

    tv.pluto.ip.dal.clip.Clips.GetComScoreByIdResponse comSoreResponse =
        clipsClient.getComScoreById(clips.getId());
    String comScoreString = new GsonBuilder().create().toJson(comSoreResponse);
    JSONObject comScoreStringJson = new JSONObject(comScoreString);

    JSONObject schemaJson = new JSONObject(stringComScore);
    Schema schema = SchemaLoader.load(comScoreStringJson);

    JSONObject responseJson = new JSONObject(schemaJson);
    schema.validate(responseJson);
  }

  @Test
  @Description("GetById - has a productionCompany array")
  @TmsLink("28500685")
  public void C28500685_TEST() {
    Clips clips = clipsUtils.getDocumentById("650d330091ee7c001ae7c2e6");
    //        Clips clips = clipsUtils.getExistsAndSizeNotZero("productionCompany");
    Assert.assertTrue(clips.getProductionCompany().size() > 0);

    Clips mappedClipGrpc =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(clips.getId()).getDocument(), Clips.class);

    Assert.assertEquals(clips.getProductionCompany(), mappedClipGrpc.getProductionCompany());
    Assert.assertEquals(clips, mappedClipGrpc);
  }

  @Test
  @Description("GetById - has a productionCountries array")
  @TmsLink("28500686")
  public void C28500686_TEST() {
    Clips clips = clipsUtils.getDocumentById("650d330091ee7c001ae7c2e6");
    //        Clips clips = clipsUtils.getExistsAndSizeNotZero("productionCompany");
    Assert.assertTrue(clips.getProductionCountries().size() > 0);

    Clips mappedClipGrpc =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(clips.getId()).getDocument(), Clips.class);

    Assert.assertEquals(clips.getProductionCountries(), mappedClipGrpc.getProductionCountries());
    Assert.assertEquals(clips, mappedClipGrpc);
  }

  @Test
  @Description("GetById - has a productionYear field")
  @TmsLink("28500687")
  public void C28500687_TEST() {
    // slow query
    int year = 2018;
    Clips clips = clipsUtils.getDocumentById("650d330091ee7c001ae7c2e6");
    //        Iterator<Clips> iteratorClips =
    // clipsUtils.getDocumentsWithTheFieldMoreThanNumber("productionYear", year);
    //        Clips clips = iteratorClips.next();
    Assert.assertTrue(clips.getProductionYear() >= year);

    Clips mappedClipGrpc =
        clipsUtils.mapGrpcObjectToPojo(
            clipsClient.getById(clips.getId()).getDocument(), Clips.class);

    Assert.assertEquals(clips.getProductionYear(), mappedClipGrpc.getProductionYear());
    Assert.assertEquals(clips, mappedClipGrpc);
  }

  @Test
  @Description("GetAllPaged - filter by name")
  @TmsLink("28500688")
  public void C28500688_TEST() {
    ClipsClient clipsClient = new ClipsClient(grpcChannelManager.getChannel(), false);
    int limit = 1;
    String name = testClip.getName();

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

    Filter filter = clipsClient.getFilter("name", name, "string");
    GetAllPagedResponse clipsAllPaged =
        clipsClient.getAllPaged(limit, 0, grpcSort, List.of(filter), true);

    Assert.assertTrue(clipsAllPaged.getDocumentsList().size() <= limit);
    Assert.assertEquals(
        clipsAllPaged.getMetadata().getTotalItems(), clipsAllPaged.getDocumentsList().size());

    List<Clip> listClips = clipsAllPaged.getDocumentsList();
    listClips.forEach(c -> Assert.assertEquals(c.getName(), name));
  }

  @Test
  @Description("GetAllPaged - filter by partner")
  @TmsLink("28500689")
  public void C28500689_TEST() {
    int limit = 5;
    BasicDBObject query = new BasicDBObject("partner", new BasicDBObject("$ne", null));

    Clips clips = (Clips) clipsUtils.getDocuments(query, 1).get(0);
    String partner = clips.getPartner();

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

    Filter filter = clipsClient.getFilter("partner", partner, "string");

    GetAllPagedResponse clipsAllPaged =
        new ClipsClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(limit, 0, grpcSort, List.of(filter), true);

    Assert.assertTrue(clipsAllPaged.getDocumentsList().size() <= limit);
    Assert.assertNotNull(clipsAllPaged);
    Assert.assertEquals(
        clipsAllPaged.getMetadata().getTotalItems(), clipsAllPaged.getDocumentsList().size());

    List<Clip> listClips = clipsAllPaged.getDocumentsList();
    listClips.forEach(c -> Assert.assertEquals(c.getPartner(), partner));
  }

  @Test
  @Description("GetByCodeAndActiveRegion - code and active region")
  @TmsLink("28500702")
  public void C28500702_TEST() {
    Clip clipGrpcToCreate = clipsClientAuth.getClipGrpcToCreate();
    Clip clipsGrpcCreate = clipsClientAuth.create(clipGrpcToCreate).getDocument();
    String code = clipsGrpcCreate.getCode();
    String activeRegion = clipsGrpcCreate.getActiveRegion();

    Clip responseClip = clipsClientAuth.getByCodeAndActiveRegion(code, activeRegion).getDocument();

    String id = responseClip.getId();
    Clips clips = clipsUtils.getDocumentById(id);
    Clips mappedClip = clipsUtils.mapGrpcObjectToPojo(responseClip, Clips.class);

    Assert.assertEquals(code, mappedClip.getCode());
    Assert.assertEquals(activeRegion, mappedClip.getActiveRegion());
    Assert.assertEquals(clips, mappedClip);

    clipsClientAuth.deleteById(id);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetByCodeAndActiveRegion - empty code but with active region")
  @TmsLink("28500703")
  public void C28500703_TEST() {
    clipsClientAuth.getByCodeAndActiveRegion("", "us");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetByCodeAndActiveRegion - empty active region but with code")
  @TmsLink("28500704")
  public void C28500704_TEST() {
    Clips clips = clipsUtils.getExistsAndNotEmpty("code");
    clipsClientAuth.getByCodeAndActiveRegion(clips.getCode(), "");
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetByCodeAndActiveRegion - no active region and invalid code")
  @TmsLink("28500705")
  public void C28500705_TEST() {
    int random = new Random().nextInt(9999);
    clipsClientAuth.getByCodeAndActiveRegion("invalidCode" + random, null);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetByCodeAndActiveRegion - invalid active region and code")
  @TmsLink("28500706")
  public void C28500706_TEST() {
    int random = new Random().nextInt(9999);
    clipsClientAuth.getByCodeAndActiveRegion("invalidCode" + random, "AA" + random);
  }

  @Test
  @Description("GetByTag - happy path")
  @TmsLink("28500707")
  public void C28500707_TEST() {
    Clip clipGrpcToCreate = clipsClientAuth.getClipGrpcToCreate();
    Clip clipsGrpcCreate = clipsClientAuth.create(clipGrpcToCreate).getDocument();
    Clip clipsGrpcCreateTwo = clipsClientAuth.create(clipGrpcToCreate).getDocument();
    String testTag = clipsGrpcCreate.getTags(0);

    Set<String> setClipIds =
        clipsClientAuth.getByTag(testTag, 0).getDocumentsList().stream()
            .map(tv.pluto.ip.dal.clip.Clips.Clip::getId)
            .collect(Collectors.toSet());

    Assert.assertFalse(setClipIds.isEmpty());

    List<Clips> listClipsWithTag = clipsUtils.getDocumentsByKeyValue("tags", testTag);
    Set<String> mongoClipIds =
        listClipsWithTag.stream().map(Clips::getId).collect(Collectors.toSet());

    Assert.assertEquals(mongoClipIds, setClipIds);
    clipsClientAuth.deleteByIds(List.of(clipsGrpcCreate.getId(), clipsGrpcCreateTwo.getId()));
  }

  @Test
  @Description("GetByTag - happy path limit")
  @TmsLink("28500708")
  public void C28500708_TEST() {
    Clip clipGrpcToCreate = clipsClientAuth.getClipGrpcToCreate();
    Clip clipsGrpcCreate = clipsClientAuth.create(clipGrpcToCreate).getDocument();
    Clip clipsGrpcCreateTwo = clipsClientAuth.create(clipGrpcToCreate).getDocument();
    String testTag = clipsGrpcCreate.getTags(0);

    Set<String> setClipIds =
        clipsClientAuth.getByTag(testTag, 1).getDocumentsList().stream()
            .map(tv.pluto.ip.dal.clip.Clips.Clip::getId)
            .collect(Collectors.toSet());

    Assert.assertFalse(setClipIds.isEmpty());

    List<Clips> listClipsWithTag = clipsUtils.getDocumentsByKeyValue("tags", testTag);
    Set<String> mongoClipIds =
        listClipsWithTag.stream().map(Clips::getId).collect(Collectors.toSet());

    Assert.assertEquals(1, setClipIds.size());
    Assert.assertTrue(mongoClipIds.containsAll(setClipIds));
    clipsClientAuth.deleteByIds(List.of(clipsGrpcCreate.getId(), clipsGrpcCreateTwo.getId()));
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("GetByTag - with a fake tag")
  @TmsLink("28500709")
  public void C28500709_TEST() {
    String fakeTag = new Faker().word().toString();
    clipsClientAuth.getByTag(fakeTag, 0);
  }

  @Test(groups = {"ttfb"})
  @Description("Check TTFB 90 percentile for the ClipManager GetByIds operation.")
  @TmsLink("28500710")
  public void C28500710_TEST() {

    Iterator clips = clipsUtils.getDocumentsWithTheField("transcode", true);
    Clips clipOne = (Clips) clips.next();
    Clips clipTwo = (Clips) clips.next();
    Clips clipThree = (Clips) clips.next();

    List<String> clipIdsList = List.of(clipOne.getId(), clipTwo.getId(), clipThree.getId());

    GrpcCall grpcCall =
        new GrpcCall("ClipManager.GetByIds", () -> clipsUtils.getDocumentsByIds(clipIdsList));

    TTFBGrpcValidator ttfbGrpcValidator = TTFBGrpcValidator.builder().build();

    ttfbGrpcValidator.validateTTFBForGrpcCalls(List.of(grpcCall));
  }

  @Test
  @Description("Valid request with multiple clips using projection - GetClipsByIds")
  @TmsLink("28500714")
  public void C28500714_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();

    String[] projection = {"_id", "name"};

    List<Clips> allMongoClipsList = clipsUtils.getDocumentsByIds(randomClipsIds, projection);
    List<Clips> mongoClipsList =
        allMongoClipsList.stream().filter(c -> !c.getIsArchived()).collect(Collectors.toList());

    List<String> projections = new ArrayList<>();
    projections.add("id");
    projections.add("name");

    List<?> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getByIds(randomClipsIds, projections).getDocumentsList(), Clips.class);

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test
  @Description("GetAllPaged using projection")
  @TmsLink("28500715")
  public void C28500715_TEST() {
    ClipsClient clipsClient = new ClipsClient(grpcChannelManager.getChannel(), false);
    List<String> projections = new ArrayList<>();
    projections.add("id");
    projections.add("name");

    GetAllPagedResponse clipsAllPaged =
        clipsClient.getAllPaged(10, 0, null, null, true, projections);

    List<Clip> listClipsGrpc = clipsAllPaged.getDocumentsList();
    List<String> listClipIds =
        listClipsGrpc.stream().map(c -> c.getId()).collect(Collectors.toList());

    String[] projection = {"_id", "name"};

    List<Clips> mongoClipsList = clipsUtils.getDocumentsByIds(listClipIds, projection);
    List<Clips> mappedClipsList = clipsUtils.mapGrpcObjectsToPojo(listClipsGrpc, Clips.class);

    mongoClipsList.sort(Comparator.comparing(Clips::getId));
    mappedClipsList.sort(Comparator.comparing(Clips::getId));

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test
  @Description("Valid request with multiple clips using a filter by id and name - GetClipsByIds")
  @TmsLink("28500716")
  public void C28500716_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();

    LogUtils.logInfoMessage(
        "Filtering by Id: " + testClip.getId() + " and Name: " + testClip.getName());

    Bson mongoFilters =
        Filters.and(
            Filters.eq("_id", new ObjectId(testClip.getId())),
            Filters.in("name", testClip.getName()));

    List<Clips> allMongoClipsList = clipsUtils.getDocumentsByIds(randomClipsIds, mongoFilters);

    List<Clips> mongoClipsList =
        allMongoClipsList.stream().filter(c -> !c.getIsArchived()).collect(Collectors.toList());

    tv.pluto.ip.dal.clip.Clips.Filter idFilter =
        tv.pluto.ip.dal.clip.Clips.Filter.newBuilder()
            .setField("_id")
            .setValue(testClip.getId())
            .setType("string")
            .setOperator("and")
            .build();

    tv.pluto.ip.dal.clip.Clips.Filter nameFilter =
        tv.pluto.ip.dal.clip.Clips.Filter.newBuilder()
            .setField("name")
            .setValue(testClip.getName())
            .setType("string")
            .setOperator("and")
            .build();

    List<tv.pluto.ip.dal.clip.Clips.Filter> filters =
        new ArrayList<tv.pluto.ip.dal.clip.Clips.Filter>();
    filters.add(idFilter);
    filters.add(nameFilter);

    List<?> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getByIdsWithFilters(randomClipsIds, filters).getDocumentsList(),
            Clips.class);

    Assert.assertEquals(mongoClipsList, mappedClipsList);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description(
      "Valid request with multiple clips using a filter by an invalid name - GetClipsByIds")
  @TmsLink("28500717")
  public void C28500717_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();

    String invalidName = new Faker().name().name();

    LogUtils.logInfoMessage("Filtering by an invalid Name: " + invalidName);

    tv.pluto.ip.dal.clip.Clips.Filter nameFilter =
        tv.pluto.ip.dal.clip.Clips.Filter.newBuilder()
            .setField("name")
            .setValue(invalidName)
            .setType("string")
            .build();

    List<tv.pluto.ip.dal.clip.Clips.Filter> filters =
        new ArrayList<tv.pluto.ip.dal.clip.Clips.Filter>();
    filters.add(nameFilter);

    clipsUtils.mapGrpcObjectsToPojo(
        clipsClient.getByIdsWithFilters(randomClipsIds, filters).getDocumentsList(), Clips.class);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = NOT_FOUND)
  @Description("Valid request with multiple clips using a filter by an empty name - GetClipsByIds")
  @TmsLink("28500718")
  public void C28500718_TEST() {
    List<String> randomClipsIds = clipsUtils.getRandomClipsIds();

    String emptyName = "";

    LogUtils.logInfoMessage("Filtering by an empty Name.");

    tv.pluto.ip.dal.clip.Clips.Filter nameFilter =
        tv.pluto.ip.dal.clip.Clips.Filter.newBuilder()
            .setField("name")
            .setValue(emptyName)
            .setType("string")
            .build();

    List<tv.pluto.ip.dal.clip.Clips.Filter> filters =
        new ArrayList<tv.pluto.ip.dal.clip.Clips.Filter>();
    filters.add(nameFilter);

    clipsUtils.mapGrpcObjectsToPojo(
        clipsClient.getByIdsWithFilters(randomClipsIds, filters).getDocumentsList(), Clips.class);
  }

  @Test
  @Description("GetPromotionalClips")
  @TmsLink("28500719")
  public void C28500719_TEST() {
    List<Clips> allMongoClipsList = clipsUtils.getPromotionalClips();

    List<Clips> mappedClipsList =
        clipsUtils.mapGrpcObjectsToPojo(
            clipsClient.getPromotionalClips().getDocumentsList(), Clips.class);

    allMongoClipsList.sort(Comparator.comparing(Clips::getId));
    mappedClipsList.sort(Comparator.comparing(Clips::getId));

    Assert.assertEquals(allMongoClipsList, mappedClipsList);
  }
}
