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

import static tv.pluto.mongo.utils.MongoUtils.INVALID_ID_VALUE;
import static tv.pluto.mongo.utils.MongoUtils.NOT_ID_VALUE;

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.TmsLink;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.episodes.EpisodesClient;
import tv.pluto.grpc.sequencer.SequencerClient;
import tv.pluto.ip.dal.sequencer.Sequencer;
import tv.pluto.mongo.entities.channels.Channels;
import tv.pluto.mongo.entities.common.RegionFilter;
import tv.pluto.mongo.entities.sequencer.Episode;
import tv.pluto.mongo.entities.sequencer.Partner;
import tv.pluto.mongo.entities.sequencer.Source;
import tv.pluto.mongo.entities.sequencer.Timeline;
import tv.pluto.mongo.entities.subclips.SubClips;
import tv.pluto.mongo.entities.timelines.Timelines;
import tv.pluto.mongo.utils.ChannelsUtils;
import tv.pluto.mongo.utils.SequencerUtils;
import tv.pluto.mongo.utils.SubClipsUtils;
import tv.pluto.mongo.utils.TimelinesUtils;
import tv.pluto.mongo.utils.episodes.EpisodeUtils;

public class SequencerTestSuite extends BaseTest {
  private SequencerClient sequencerClient;
  private EpisodeUtils episodeUtils;
  private ChannelsUtils channelsUtils;
  private SequencerUtils sequencerUtils;
  private TimelinesUtils timelinesUtils;
  private SubClipsUtils subClipUtils;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    // Initialize utils
    episodeUtils = new EpisodeUtils();
    channelsUtils = new ChannelsUtils();
    sequencerUtils = new SequencerUtils();
    timelinesUtils = new TimelinesUtils();
    subClipUtils = new SubClipsUtils();

    // Create a ChannelsClient using the in-process channel;
    sequencerClient = new SequencerClient(grpcChannelManager.getChannel());
  }

  @Test
  @Description("Valid request:Episode with series - GetHydratedEpisode")
  @TmsLink("28501302")
  public void C28501302_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithSeries();
    LogUtils.logInfoMessage("EpisodeId: " + randomEpisodeId);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);
    String clipId = mongoEpisode.getSources().get(0).getClip().getId();

    Source mongoSource =
        mongoEpisode.getSources().stream()
            .filter(source -> source.getClip().getId().equals(clipId))
            .findFirst()
            .orElseThrow(
                () ->
                    new RuntimeException("Clip with the specified ID not found in mappedEpisode"));
    Source mappedSource =
        mappedEpisode.getSources().stream()
            .filter(source -> source.getClip().getId().equals(clipId))
            .findFirst()
            .orElseThrow(
                () ->
                    new RuntimeException("Clip with the specified ID not found in mappedEpisode"));
    Assert.assertEquals(mongoSource, mappedSource);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Issue("ARCH-416")
  @Description("Valid request:Episode without series - GetHydratedEpisode")
  @TmsLink("28501303")
  public void C28501303_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithoutSeries();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Issue("ARCH-416")
  @Description("Valid request:Episode with clips in sources - GetHydratedEpisode")
  @TmsLink("28501304")
  public void C28501304_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithSources();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Issue("ARCH-416")
  @Description("Valid request:Episode without clips in sources - GetHydratedEpisode")
  @TmsLink("28501305")
  public void C28501305_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithoutSources();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Description("Valid request:Episode where clips have partner - GetHydratedEpisode")
  @TmsLink("28501306")
  public void C28501306_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithPartner();

    LogUtils.logInfoMessage("C796368_TEST episode id = " + randomEpisodeId);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Issue("ARCH-416")
  @Description("Valid request:Episode where clips don't have partner - GetHydratedEpisode")
  @TmsLink("28501307")
  public void C28501307_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithoutPartner();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Description(
      "Valid request:Episode where clips have partner and partner has comScore data - GetHydratedEpisode")
  @TmsLink("28501308")
  public void C28501308_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithPartnerWithComScore();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Description(
      "Valid request:Episode where clips have partner, but partner doesn't have comScore data - GetHydratedEpisode")
  @TmsLink("28501309")
  public void C28501309_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithPartnerWithoutComScore();

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Episode for requested ID not found: Sequencer")
  @Description("Invalid request - GetHydratedEpisode")
  @TmsLink("28501310")
  public void C28501310_TEST() {
    sequencerClient.getHydratedEpisode(INVALID_ID_VALUE);
  }

  @Test
  @Description("Valid request: Timeline where episode has series - GetHydratedTimeline")
  @TmsLink("28501311")
  public void C28501311_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithSeries();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);
    String clipId = mongoTimeline.getEpisode().getSources().get(0).getClip().getId();

    Source mongoSource =
        mongoTimeline.getEpisode().getSources().stream()
            .filter(source -> source.getClip().getId().equals(clipId))
            .findFirst()
            .orElseThrow(
                () ->
                    new RuntimeException("Clip with the specified ID not found in mongoTimeline"));

    Source mappedSource =
        mappedTimeline.getEpisode().getSources().stream()
            .filter(source -> source.getClip().getId().equals(clipId))
            .findFirst()
            .orElseThrow(
                () ->
                    new RuntimeException("Clip with the specified ID not found in mappedTimeline"));

    Assert.assertEquals(
        mongoSource.getClip().getBreakpoints(), mappedSource.getClip().getBreakpoints());

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test
  @Description("Valid request: Timeline where episode doesn't have series - GetHydratedTimeline")
  @TmsLink("28500264")
  public void C28500264_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithoutSeries();

    if (!randomTimelineId.isEmpty()) {
      Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

      Timeline mappedTimeline =
          episodeUtils.mapGrpcObjectToPojo(
              sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

      sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
      sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

      mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
      mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

      Assert.assertEquals(mongoTimeline, mappedTimeline);
    } else {
      LogUtils.logInfoMessage("No data was found for C827017_TEST");
    }
  }

  @Test
  @Description("Valid request: Timeline where episode have clips in sources - GetHydratedTimeline")
  @TmsLink("28501312")
  public void C28501312_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithClips();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
    mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test
  @Description("Valid request: Timeline where episode's clips have partner - GetHydratedTimeline")
  @TmsLink("28501313")
  public void C28501313_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithPartner();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
    mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  // Run locally. Runs too long
  @Test(enabled = false) // TODO fix test data
  @Description(
      "Valid request: Timeline where episode's clips don't have partner - GetHydratedTimeline")
  @TmsLink("28501314")
  public void C28501314_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithoutPartner();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test
  @Description(
      "Valid request: Timeline where episode's clips have partner, and partner has comScore data - GetHydratedTimeline")
  @TmsLink("28501315")
  public void C28501315_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithComScore();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
    mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test
  @Issue("ARCH-948")
  @Description(
      "Valid request: Timeline where episode's clips have partner, and partner don't have comScore data - GetHydratedTimeline")
  @TmsLink("28501316")
  public void C28501316_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithoutComScore();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(randomTimelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
    mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Timeline for requested ID not found: Sequencer")
  @Description("Invalid request - GetHydratedTimeline")
  @TmsLink("28501317")
  public void C28501317_TEST() {
    sequencerClient.getHydratedTimeline(INVALID_ID_VALUE);
  }

  @Test
  @Description("Invalid id request - GetHydratedTimeline")
  @TmsLink("28501318")
  public void C28501318_TEST() {
    try {
      sequencerClient.getHydratedTimeline(NOT_ID_VALUE);
    } catch (RuntimeException e) {
      Assert.assertTrue(e.getMessage().contains("INTERNAL: Cast to ObjectId failed for value"));
    }
  }

  @Test
  @Description("GetHydratedEpisode - episode with age range")
  @TmsLink("28501319")
  public void C28501319_TEST() {
    String randomEpisodeId = episodeUtils.getIdsOfEpisodesWithAgeRange(1).get(0);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Description("GetHydratedEpisode - episode without age range")
  @TmsLink("28501320")
  public void C28501320_TEST() {
    String randomEpisodeId = episodeUtils.getIdsOfEpisodesWithoutAgeRange(2).get(1);

    // internalClip can be null when test data issue
    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    sequencerUtils.sortInnerLists(mongoEpisode);
    sequencerUtils.sortInnerLists(mappedEpisode);

    Assert.assertEquals(mongoEpisode, mappedEpisode);
  }

  @Test
  @Description(
      "GetHydratedTimeline - Timeline where episode's clips have partner,some of the clips have genre, and partner has comScore data")
  @TmsLink("28501321")
  public void C28501321_TEST() {
    // Hardcoded to reduce the time of execution
    Timelines timelineIds = timelinesUtils.getRandomDocument();
    String timelineId = timelineIds.getId();

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(timelineId);

    Timeline mappedTimeline =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedTimeline(timelineId).getTimeline(), Timeline.class);

    sequencerUtils.sortInnerLists(mongoTimeline.getEpisode());
    sequencerUtils.sortInnerLists(mappedTimeline.getEpisode());

    mongoTimeline = sequencerUtils.getTimelinesNotNulls(mongoTimeline);
    mappedTimeline = sequencerUtils.getTimelinesNotNulls(mappedTimeline);

    Assert.assertEquals(mongoTimeline, mappedTimeline);
  }

  @Test
  @Description("GetHydratedTimeline - contains channel_populated object")
  @TmsLink("28501322")
  public void C28501322_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithSeries();
    LogUtils.logInfoMessage("C21891529_TEST. Test timeline id: " + randomTimelineId);

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);
    Channels mongoChannels = channelsUtils.getDocumentById(mongoTimeline.getChannel());

    tv.pluto.mongo.entities.channels.Channels channels =
        channelsUtils.getDocumentById(mongoTimeline.getChannel());
    Assert.assertEquals(channels.getDistribution(), mongoChannels.getDistribution());
  }

  @Test
  @Description(
      "GetHydratedTimeline - channel_populated object contains include and exclude objects")
  @TmsLink("28501323")
  public void C28501323_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithSeries();
    LogUtils.logInfoMessage("Test timeline id: " + randomTimelineId);

    Timeline mongoTimeline = sequencerUtils.getHydratedTimeline(randomTimelineId);
    Channels mongoChannels = channelsUtils.getDocumentById(mongoTimeline.getChannel());

    tv.pluto.mongo.entities.channels.Channels channels =
        channelsUtils.getDocumentById(mongoTimeline.getChannel());
    RegionFilter distribution = channels.getDistribution();

    Assert.assertNotNull(distribution);
    Assert.assertEquals(distribution, mongoChannels.getDistribution());
    Assert.assertNotNull(distribution.getInclude());
    Assert.assertNotNull(distribution.getExclude());
  }

  @Test
  @Description("GetHydratedEpisode - clip.partner return the empty object")
  @TmsLink("28501324")
  public void C28501324_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithSeries();
    LogUtils.logInfoMessage("EpisodeId: " + randomEpisodeId);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    for (Source source : mongoEpisode.getSources()) {
      Partner partner = source.getClip().getPartner();
      Source sourceMappedEpisode =
          mappedEpisode.getSources().stream()
              .filter(s -> s.getClip().getId().equals(source.getClip().getId()))
              .findFirst()
              .orElseThrow(() -> new RuntimeException("Clip wasn't found"));

      Partner partnerGrpc = sourceMappedEpisode.getClip().getPartner();

      if (partner == null) Assert.assertNull(partnerGrpc);
      else Assert.assertEquals(partnerGrpc, partner);
    }
  }

  @Test
  @Description("GetHydratedEpisode - FAILED_PRECONDITION")
  @TmsLink("28501325")
  public void C28501325_TEST() {
    boolean isThrown = false;
    EpisodesClient authEpisodesClient = new EpisodesClient(grpcChannelManager.getChannel(), true);
    String episodeID = episodeUtils.createNewEpisodeId(authEpisodesClient);

    long updatedClip = episodeUtils.updateClipIdInSources(episodeID, INVALID_ID_VALUE);
    Assert.assertEquals(updatedClip, 1);

    try {
      sequencerClient.getHydratedEpisode(episodeID);
    } catch (RuntimeException e) {
      Assert.assertTrue(e.getMessage().contains("FAILED_PRECONDITION"));
      isThrown = true;
    }
    Assert.assertTrue(isThrown);

    authEpisodesClient.deleteById(episodeID);
  }

  @Test(groups = {"ttfb"})
  @Description("Check TTFB 90 percentile for the SequencerManager GetHydratedTimeline operation.")
  @TmsLink("28501326")
  public void C28501326_TEST() {
    String randomTimelineId = timelinesUtils.getIdOfTimelineWithSeries();

    GrpcCall grpcCall =
        new GrpcCall(
            "SequencerManager.GetHydratedTimeline",
            () -> sequencerClient.getHydratedTimeline(randomTimelineId));

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

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

  @Test
  @Description("GetHydratedEpisode - Episode where Clips have contentStatus.")
  @TmsLink("28501327")
  public void C28501327_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithContentStatus(true);

    LogUtils.logInfoMessage("C33739337_TEST episode id = " + randomEpisodeId);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    for (Source source : mongoEpisode.getSources()) {
      String contentStatus = source.getClip().getContentStatus();

      Source sourceMappedEpisode =
          mappedEpisode.getSources().stream()
              .filter(s -> s.getClip().getId().equals(source.getClip().getId()))
              .findFirst()
              .orElseThrow(() -> new RuntimeException("Clip wasn't found"));

      String contentStatusGrpc = sourceMappedEpisode.getClip().getContentStatus();

      if (contentStatus == null) Assert.assertNull(contentStatusGrpc);
      else Assert.assertEquals(contentStatusGrpc, contentStatus);
    }
  }

  @Test
  @Description("GetHydratedEpisode - Episode subClips double duration")
  @TmsLink("28501329")
  public void C28501329_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithDuration();
    LogUtils.logInfoMessage("C34063065. Episode id = " + randomEpisodeId);

    Sequencer.Episode grpcEpisode =
        sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode();

    Map<String, Float> mapIdDuration =
        grpcEpisode.getSourcesList().stream()
            .flatMap(source -> source.getClip().getFragmentsList().stream())
            .flatMap(fragment -> fragment.getSubClipsList().stream())
            .collect(Collectors.toMap(Sequencer.SubClip::getId, Sequencer.SubClip::getDuration));

    List<String> listSubIds = mapIdDuration.keySet().stream().toList();
    List<SubClips> listSubClips = subClipUtils.getDocumentsByIds(listSubIds);

    Assert.assertFalse(listSubClips.isEmpty(), "SubClips list is empty");
    mapIdDuration.forEach(
        (key, value) -> {
          listSubClips.stream()
              .filter(c -> c.getId().equals(key))
              .forEach(
                  c -> {
                    Assert.assertEquals(
                        c.getDuration(), value.doubleValue(), "Duration is not equal");
                  });
        });
  }

  @Test
  @Description("GetHydratedEpisode - Episode where Clips don't have contentStatus.")
  @TmsLink("28501328")
  public void C28501328_TEST() {
    String randomEpisodeId = episodeUtils.getIdOfEpisodeWithContentStatus(false);

    LogUtils.logInfoMessage("C33739338_TEST episode id = " + randomEpisodeId);

    Episode mongoEpisode = sequencerUtils.getHydratedEpisode(randomEpisodeId);

    Episode mappedEpisode =
        episodeUtils.mapGrpcObjectToPojo(
            sequencerClient.getHydratedEpisode(randomEpisodeId).getEpisode(), Episode.class);

    for (Source source : mongoEpisode.getSources()) {
      String contentStatus = source.getClip().getContentStatus();

      Source sourceMappedEpisode =
          mappedEpisode.getSources().stream()
              .filter(s -> s.getClip().getId().equals(source.getClip().getId()))
              .findFirst()
              .orElseThrow(() -> new RuntimeException("Clip wasn't found"));

      String contentStatusGrpc = sourceMappedEpisode.getClip().getContentStatus();

      if (contentStatus == null) Assert.assertNull(contentStatusGrpc);
      else Assert.assertEquals(contentStatusGrpc, contentStatus);
    }
  }
}
