package tv.pluto;

import static tv.pluto.ip.dal.featuredgroup.FeaturedGroups.Filter;

import com.plutotv.test.lib.LogUtils;
import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.TmsLink;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import net.datafaker.Faker;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import tv.pluto.core.BaseTest;
import tv.pluto.grpc.featured_group.FeaturedGroupClient;
import tv.pluto.ip.dal.featuredgroup.FeaturedGroups;
import tv.pluto.mongo.entities.channels.Channels;
import tv.pluto.mongo.entities.featuredgroup.ContentItems;
import tv.pluto.mongo.entities.featuredgroup.FeaturedGroup;
import tv.pluto.mongo.utils.ChannelsUtils;
import tv.pluto.mongo.utils.FeaturedGroupUtils;
import tv.pluto.utils.CommonUtils;

public class FeaturedGroupTestSuite extends BaseTest {
  private FeaturedGroupUtils featuredGroupUtils;
  private ChannelsUtils channelsUtils;
  private FeaturedGroupClient featuredGroupClient;
  private FeaturedGroupClient featuredGroupClientAuth;
  private FeaturedGroup featuredGroup = null;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    featuredGroupUtils = new FeaturedGroupUtils();
    channelsUtils = new ChannelsUtils();
    featuredGroupClient = new FeaturedGroupClient(grpcChannelManager.getChannel(), false);
    featuredGroupClientAuth = new FeaturedGroupClient(grpcChannelManager.getChannel(), true);

    List<String> listValidEmails = List.of("melanie.baron@pluto.tv", "martin.bascal@pluto.tv");
    List<FeaturedGroup> listFeaturedGroup = featuredGroupUtils.getRandomDocuments(1000);

    List<FeaturedGroup> listFilteredFeaturedGroup =
        listFeaturedGroup.stream()
            .filter(
                f ->
                    f.getAuthor().equals(listValidEmails.get(0))
                        || f.getAuthor().equals(listValidEmails.get(1)))
            .collect(Collectors.toList());

    if (listFilteredFeaturedGroup.isEmpty()) {
      // cms team has a validation from their side. The email should be valid
      featuredGroup = featuredGroupUtils.getRandomDocument();
    } else featuredGroup = listFilteredFeaturedGroup.get(0);

    Assert.assertNotNull(featuredGroup);
  }

  @Test
  @Description("GetById - verify the response")
  @TmsLink("28500976")
  public void C28500976_TEST() {
    FeaturedGroups.PopulatedFeaturedGroup byId =
        featuredGroupClient.getById(featuredGroup.getId()).getDocument();
    List<String> listContentIds =
        byId.getContentItemsList().stream()
            .map(c -> c.getContent().getId())
            .collect(Collectors.toList());
    List<String> listContentIdsMongoDb =
        featuredGroup.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());

    Assert.assertEquals(listContentIds, listContentIdsMongoDb);
    Assert.assertEquals(byId.getActiveRegion(), featuredGroup.getActiveRegion());
    Assert.assertEquals(byId.getAuthor(), featuredGroup.getAuthor());
    Assert.assertEquals(byId.getId(), featuredGroup.getId());
    Assert.assertEquals(byId.getName(), featuredGroup.getName());
    Assert.assertEquals(byId.getPublished(), featuredGroup.getPublished());
  }

  @Test
  @Description("GetEpisodeById - categories.name")
  @TmsLink("28500977")
  public void C28500977_TEST() {
    FeaturedGroups.GetByIdResponse byId = featuredGroupClient.getById(featuredGroup.getId());
    List<FeaturedGroups.PopulatedContentItem> contentItemsList =
        byId.getDocument().getContentItemsList();

    List<String> listIds =
        contentItemsList.stream().map(c -> c.getContent().getId()).collect(Collectors.toList());
    List<Channels> listChannels = channelsUtils.getDocumentsByIds(listIds);

    contentItemsList.forEach(
        content -> {
          String channelId = content.getContent().getId();
          String name = content.getContent().getName();
          LogUtils.logInfoMessage("channelId: " + channelId + ", name: " + name);

          Channels channel =
              listChannels.stream().filter(c -> c.getId().equals(channelId)).findFirst().get();
          Assert.assertNotNull(channel);
          Assert.assertEquals(channel.getName(), name);
        });
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: No FeaturedGroup documents found for ID")
  @Description("GetById - invalid id")
  @TmsLink("28500978")
  public void C28500978_TEST() {
    featuredGroupClient.getById(INVALID_ID);
  }

  @Test
  @Description("GetAllPaged - compare with GetById response")
  @TmsLink("28500979")
  public void C28500979_TEST() {
    FeaturedGroups.GetAllPagedResponse getAllPaged =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(1, 0, null, null, true);
    Assert.assertEquals(1, getAllPaged.getDocumentsList().size());

    FeaturedGroups.GetAllPagedFeaturedGroup getAllPagedFeaturedGroup =
        getAllPaged.getDocumentsList().get(0);
    FeaturedGroups.PopulatedFeaturedGroup byId =
        featuredGroupClient.getById(getAllPaged.getDocumentsList().get(0).getId()).getDocument();

    Assert.assertEquals(getAllPagedFeaturedGroup.getId(), byId.getId());
    Assert.assertEquals(getAllPagedFeaturedGroup.getActiveRegion(), byId.getActiveRegion());
    Assert.assertEquals(getAllPagedFeaturedGroup.getAuthor(), byId.getAuthor());
    Assert.assertEquals(getAllPagedFeaturedGroup.getEnd(), byId.getEnd());
    Assert.assertEquals(getAllPagedFeaturedGroup.getName(), byId.getName());
    Assert.assertEquals(getAllPagedFeaturedGroup.getCreatedAt(), byId.getCreatedAt());
    Assert.assertEquals(getAllPagedFeaturedGroup.getStart(), byId.getStart());
  }

  @Test(dataProvider = "sort-values")
  @TmsLink("28500980")
  @Description("GetAllPaged - sort by name")
  public void C28500980_TEST(int sort) {
    List<FeaturedGroups.GetAllPagedSort> grpcSort =
        List.of(
            FeaturedGroups.GetAllPagedSort.newBuilder().setField("name").setValue(sort).build());

    FeaturedGroups.GetAllPagedResponse getAllPaged =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(3, 0, grpcSort, null, true);
    Assert.assertEquals(3, getAllPaged.getDocumentsList().size());

    List<String> getAllPagedNameList =
        getAllPaged.getDocumentsList().stream()
            .map(FeaturedGroups.GetAllPagedFeaturedGroup::getName)
            .collect(Collectors.toList());

    List<String> listSorted = new ArrayList<>(getAllPagedNameList);

    if (sort == 1) Collections.sort(listSorted, new CommonUtils.NumericStringComparator());
    else
      Collections.sort(
          listSorted, Collections.reverseOrder(new CommonUtils.NumericStringComparator()));

    Assert.assertEquals(getAllPagedNameList, listSorted);
  }

  @Test
  @Description("GetAllPaged - filter by id")
  @TmsLink("28500981")
  public void C28500981_TEST() {
    List<FeaturedGroups.GetAllPagedSort> grpcSort =
        List.of(FeaturedGroups.GetAllPagedSort.newBuilder().setField("name").setValue(1).build());

    List<Filter> listFilter =
        Collections.singletonList(
            Filter.newBuilder()
                .setField("_id")
                .setValue(featuredGroup.getId())
                .setType("string")
                .build());

    FeaturedGroups.GetAllPagedResponse getAllPaged =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(100, 0, grpcSort, listFilter, true);
    Assert.assertEquals(1, getAllPaged.getDocumentsList().size());

    FeaturedGroups.GetAllPagedFeaturedGroup getAllPagedFeaturedGroup =
        getAllPaged.getDocumentsList().get(0);
    Assert.assertEquals(getAllPagedFeaturedGroup.getId(), featuredGroup.getId());
    Assert.assertEquals(
        getAllPagedFeaturedGroup.getActiveRegion(), featuredGroup.getActiveRegion());
    Assert.assertEquals(getAllPagedFeaturedGroup.getAuthor(), featuredGroup.getAuthor());
    Assert.assertEquals(getAllPagedFeaturedGroup.getName(), featuredGroup.getName());
  }

  @Test
  @Description("Create - a new valid Featured Group with few valid fields")
  @TmsLink("28500982")
  public void C28500982_TEST() {
    // valid email: martin.bascal@pluto.tv
    FeaturedGroups.CreateRequest createRequest =
        featuredGroupClientAuth.getNewFeaturedGroup(featuredGroup, null, true);
    FeaturedGroups.FeaturedGroup response =
        featuredGroupClientAuth.create(createRequest).getDocument();

    Assert.assertFalse(response.getId().isEmpty());
    FeaturedGroups.PopulatedFeaturedGroup dbResponse =
        featuredGroupClientAuth.getById(response.getId()).getDocument();
    //        FeaturedGroups.FeaturedGroup dbResponse =
    // featuredGroupClientAuth.getById(response.getId()).getDocument();

    Instant start = Instant.parse(response.getStart());
    Instant startFromBuild = Instant.parse(dbResponse.getStart());
    Instant end = Instant.parse(response.getStart());
    Instant endFromBuild = Instant.parse(dbResponse.getStart());

    Assert.assertEquals(response.getActiveRegion(), dbResponse.getActiveRegion());
    Assert.assertEquals(response.getName(), dbResponse.getName());
    Assert.assertEquals(response.getAuthor(), dbResponse.getAuthor());
    Assert.assertTrue(response.getSlug().contains(dbResponse.getSlug()));
    Assert.assertEquals(start.getEpochSecond(), startFromBuild.getEpochSecond());
    Assert.assertEquals(end.getEpochSecond(), endFromBuild.getEpochSecond());

    featuredGroupClientAuth.deleteByIds(List.of(response.getId()));
  }

  @Test
  @Description("Create - a new valid Featured Group by default Published flag false")
  @TmsLink("28500983")
  public void C28500983_TEST() {
    Instant time = Instant.now().minusSeconds(90);
    Instant endTime = Instant.now();

    FeaturedGroups.FeaturedGroup docBuild =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setActiveRegion(featuredGroup.getActiveRegion())
            .setName(featuredGroup.getName())
            .setAuthor(featuredGroup.getAuthor())
            .setStart(time.toString())
            .setEnd(endTime.toString())
            .build();

    FeaturedGroups.CreateRequest createRequest =
        FeaturedGroups.CreateRequest.newBuilder().setDocument(docBuild).build();

    FeaturedGroups.FeaturedGroup response =
        featuredGroupClientAuth.create(createRequest).getDocument();

    FeaturedGroups.PopulatedFeaturedGroup document =
        featuredGroupClient.getById(response.getId()).getDocument();
    Assert.assertFalse(document.getPublished());

    featuredGroupClientAuth.deleteByIds(List.of(response.getId()));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "UNAUTHENTICATED: DB writes not allowed without authentication")
  @Description("Create - a new valid Featured Group with few valid fields without auth token")
  @TmsLink("28500984")
  public void C28500984_TEST() {
    FeaturedGroups.FeaturedGroup docBuild =
        FeaturedGroups.FeaturedGroup.newBuilder().setActiveRegion("US").build();
    FeaturedGroups.CreateRequest createRequest =
        FeaturedGroups.CreateRequest.newBuilder().setDocument(docBuild).build();
    featuredGroupClient.create(createRequest);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("Create - a new valid Featured Group an invalid user")
  @TmsLink("28500985")
  public void C28500985_TEST() {
    FeaturedGroup newFeaturedGroup = featuredGroupUtils.getRandomDocument();
    newFeaturedGroup.setAuthor("invalidDalEmail@pluto.tv");

    FeaturedGroups.CreateRequest createRequest =
        featuredGroupClientAuth.getNewFeaturedGroup(newFeaturedGroup, null, true);
    featuredGroupClientAuth.create(createRequest);
  }

  @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "INTERNAL.*")
  @Description("Create - a new valid Featured Group an invalid email format")
  @TmsLink("28500986")
  public void C28500986_TEST() {
    FeaturedGroups.FeaturedGroup build =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setActiveRegion("us")
            .setName("test")
            .setAuthor("notEmail")
            .setSlug("slug")
            .setStart(Instant.now().minusSeconds(60).toString())
            .setEnd(Instant.now().toString())
            .build();

    FeaturedGroups.CreateRequest createRequest =
        FeaturedGroups.CreateRequest.newBuilder().setDocument(build).build();
    new FeaturedGroupClient(grpcChannelManager.getChannel(), true).create(createRequest);
  }

  @Test
  @Description("DeleteByIds - valid ids with auth token")
  @TmsLink("28500987")
  public void C28500987_TEST() {
    FeaturedGroups.CreateRequest createRequest =
        featuredGroupClient.getNewFeaturedGroup(featuredGroup, null, true);
    String idOne = featuredGroupClientAuth.create(createRequest).getDocument().getId();
    String idTwo = featuredGroupClientAuth.create(createRequest).getDocument().getId();
    String idThree = featuredGroupClientAuth.create(createRequest).getDocument().getId();
    List<String> listIds = List.of(idOne, idTwo, idThree);
    LogUtils.logInfoMessage("Created the id list: " + listIds);

    FeaturedGroups.DeleteByIdsResponse deleteResponse =
        featuredGroupClientAuth.deleteByIds(listIds);
    Assert.assertEquals(listIds.size(), deleteResponse.getDeletedCount());
    boolean deleted = false;

    try {
      new FeaturedGroupClient(grpcChannelManager.getChannel(), false).deleteByIds(listIds);
    } catch (StatusRuntimeException e) {
      deleted = true;
      Assert.assertEquals(
          e.getMessage(), "NOT_FOUND: FeaturedGroup documents for requested IDs not found");
    }
    Assert.assertTrue(deleted);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "UNAUTHENTICATED: DB deletes not allowed without authentication")
  @Description("DeleteByIds - valid ids with no auth token")
  @TmsLink("28500988")
  public void C28500988_TEST() {
    FeaturedGroups.CreateRequest createRequest =
        featuredGroupClient.getNewFeaturedGroup(featuredGroup, null, true);
    String idOne = featuredGroupClientAuth.create(createRequest).getDocument().getId();
    featuredGroupClient.deleteByIds(List.of(idOne));
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: FeaturedGroup documents for requested IDs not found")
  @Description("DeleteByIds - invalid ids with auth token")
  @TmsLink("28500989")
  public void C28500989_TEST() {
    List<String> listInvalidIds = List.of("00016cd5f103d60013300000", INVALID_ID);
    new FeaturedGroupClient(grpcChannelManager.getChannel(), true).deleteByIds(listInvalidIds);
  }

  @Test
  @Description("Unpublished - published false")
  @TmsLink("28500993")
  public void C28500993_TEST() {
    FeaturedGroup featured = featuredGroupUtils.getRandomDocument();
    FeaturedGroups.FeaturedGroup unpublishedClient =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getUnpublished(featured.getId());

    long nowSeconds = Instant.now().getEpochSecond() / 60;
    long updatedInSeconds = Instant.parse(unpublishedClient.getUpdatedAt()).getEpochSecond() / 60;
    FeaturedGroup unpublishedConverted =
        featuredGroupUtils.mapGrpcObjectToPojo(unpublishedClient, FeaturedGroup.class);
    LogUtils.logInfoMessage(
        "id: " + featured.getId() + ", published: " + unpublishedClient.getPublished());

    Assert.assertEquals(nowSeconds, updatedInSeconds);
    Assert.assertFalse(unpublishedClient.getPublished());
    featured.setUpdatedAt(null);
    unpublishedConverted.setUpdatedAt(null);
    featured.setPublished(false);
    Assert.assertEquals(featured, unpublishedConverted);

    List<String> channels =
        unpublishedConverted.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());
    List<Channels> listChannels = channelsUtils.getDocumentsByIds(channels);
    listChannels.forEach(c -> Assert.assertEquals(-1, c.getFeatured()));
  }

  @Test(dataProvider = "is-true-false")
  @Description("UpdateFields - happy path")
  @TmsLink("28500990")
  public void C28500990_TEST(boolean isTrue) {
    int oneMinute = 60;
    FeaturedGroup doc = featuredGroupUtils.getDocumentByKeyValue("published", isTrue);

    if (doc == null) {
      FeaturedGroups.CreateRequest createRequest =
          new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
              .getNewFeaturedGroup(featuredGroup, null, true);
      FeaturedGroups.FeaturedGroup response =
          new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
              .create(createRequest)
              .getDocument();
      doc = featuredGroupUtils.mapGrpcObjectToPojo(response, FeaturedGroup.class);
    }

    boolean isPublished = doc.getPublished();
    LogUtils.logInfoMessage("Published: " + isPublished);
    Instant start = null;
    Instant end = null;

    if (doc.getStart() == null) start = Instant.now().minusSeconds(999);
    else start = doc.getStart().toInstant().plusSeconds(10);

    if (doc.getEnd() == null) {
      end = start.plusSeconds(99);
    } else end = doc.getEnd().toInstant().plusSeconds(10);

    FeaturedGroups.FeaturedGroup build =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setId(doc.getId())
            .setSlug(doc.getSlug() + "-dal")
            .setAuthor("dal")
            .setName("name")
            .setActiveRegion("US")
            .setStart(start.toString())
            .setEnd(end.toString())
            .setPublished(!isPublished)
            .build();

    List<String> listUpdates =
        List.of("slug", "published", "name", "author", "activeRegion", "start", "end");
    FeaturedGroups.UpdateFieldsRequest request =
        FeaturedGroups.UpdateFieldsRequest.newBuilder()
            .setDocument(build)
            .addAllUpdateFields(listUpdates)
            .build();

    FeaturedGroups.FeaturedGroup document =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .updateById(request)
            .getDocument();
    long epochSecondResponse = Instant.parse(document.getUpdatedAt()).getEpochSecond() / oneMinute;
    LogUtils.logInfoMessage("Updated at: " + document.getUpdatedAt());

    Assert.assertEquals(epochSecondResponse, Instant.now().getEpochSecond() / oneMinute);
    Assert.assertEquals(document.getId(), build.getId());
    Assert.assertEquals(document.getSlug(), build.getSlug());
    Assert.assertEquals(document.getName(), build.getName());
    Assert.assertEquals(document.getAuthor(), build.getAuthor());
    Assert.assertEquals(document.getActiveRegion(), build.getActiveRegion());
    Assert.assertEquals(document.getPublished(), isPublished);

    long updatedStart = Instant.parse(document.getStart()).getEpochSecond() / oneMinute;
    long updatedEnd = Instant.parse(document.getEnd()).getEpochSecond() / oneMinute;
    Assert.assertEquals(start.getEpochSecond() / oneMinute, updatedStart);
    Assert.assertEquals(end.getEpochSecond() / oneMinute, updatedEnd);

    String startTime;
    String endTime;

    if (doc.getStart() == null) startTime = Instant.now().minusSeconds(60).toString();
    else startTime = doc.getStart().toInstant().toString();

    if (doc.getEnd() == null) endTime = Instant.now().toString();
    else endTime = doc.getEnd().toInstant().toString();

    FeaturedGroups.FeaturedGroup buildRevert =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setId(doc.getId())
            .setSlug(doc.getSlug())
            .setAuthor(doc.getAuthor())
            .setName(doc.getName())
            .setActiveRegion(doc.getActiveRegion())
            .setStart(startTime)
            .setEnd(endTime)
            .setPublished(!doc.getPublished())
            .build();

    FeaturedGroups.UpdateFieldsRequest revertDoc =
        FeaturedGroups.UpdateFieldsRequest.newBuilder()
            .setDocument(buildRevert)
            .addAllUpdateFields(listUpdates)
            .build();
    FeaturedGroups.FeaturedGroup revResponse =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .updateById(revertDoc)
            .getDocument();
    Assert.assertEquals(revResponse.getPublished(), isPublished);
  }

  @Test
  @Description("UpdateFields - content items")
  @TmsLink("28500991")
  public void C28500991_TEST() {
    List<FeaturedGroup> listDocPublished =
        featuredGroupUtils.getDocumentsByKeyValue("published", true, 20);
    String id;

    if (listDocPublished.isEmpty()) {
      FeaturedGroups.CreateRequest createRequest =
          new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
              .getNewFeaturedGroup(featuredGroup, true, true);
      id = featuredGroupClientAuth.create(createRequest).getDocument().getId();
    } else id = listDocPublished.get(listDocPublished.size() - 1).getId();

    LogUtils.logInfoMessage("Updated featured id: " + id);
    FeaturedGroups.PopulatedFeaturedGroup doc =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false).getById(id).getDocument();

    List<FeaturedGroups.PopulatedContentItem> contentItemsList = doc.getContentItemsList();
    LogUtils.logInfoMessage("Size of content items: " + contentItemsList.size());

    List<FeaturedGroups.ContentItem> listUpdatedContent = new ArrayList<>();
    List<String> listUpdatedIds = new ArrayList<>();

    for (FeaturedGroups.PopulatedContentItem contentItem : contentItemsList) {
      String updateId = contentItem.getContent().getId();

      listUpdatedIds.add(updateId);

      FeaturedGroups.ContentItem item =
          FeaturedGroups.ContentItem.newBuilder()
              .setContent(updateId)
              .setType(contentItem.getType() + "!")
              .setStrategy(contentItem.getStrategy() + "!")
              .setNotes(contentItem.getNotes() + "!")
              .build();

      listUpdatedContent.add(item);
    }

    FeaturedGroups.FeaturedGroup build =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setId(id)
            .addAllContentItems(listUpdatedContent)
            .build();

    FeaturedGroups.UpdateFieldsRequest request =
        FeaturedGroups.UpdateFieldsRequest.newBuilder()
            .setDocument(build)
            .addAllUpdateFields(List.of("contentItems"))
            .build();

    FeaturedGroups.FeaturedGroup document =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .updateById(request)
            .getDocument();
    List<Channels> updatedList = channelsUtils.getDocumentsByIds(listUpdatedIds);

    for (int i = 0; i < listUpdatedIds.size(); i++) {
      String idToCheck = listUpdatedIds.get(i);
      Optional<Channels> matchedObject =
          updatedList.stream().filter(e -> e.getId().equals(idToCheck)).findFirst();

      Assert.assertEquals(listUpdatedIds.get(i), document.getContentItems(i).getContent());
      Assert.assertTrue(
          matchedObject.isPresent(), "Object with ID " + idToCheck + " not found in updatedList");
      Assert.assertEquals(
          i + 1,
          matchedObject.get().getFeatured(),
          "Featured value mismatch for object with ID " + idToCheck);
    }
  }

  @Test
  @Description("UpdateFields - removed and add items")
  @TmsLink("28500992")
  public void C28500992_TEST() {
    FeaturedGroups.CreateRequest createRequest =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
            .getNewFeaturedGroup(featuredGroup, true, true);

    String createdFeature =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
            .create(createRequest)
            .getDocument()
            .getId();
    FeaturedGroup featuredGroupCreated = featuredGroupUtils.getDocumentById(createdFeature);

    String id = featuredGroupCreated.getId();
    LogUtils.logInfoMessage("Updated featured id: " + id);
    FeaturedGroups.PopulatedFeaturedGroup doc =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false).getById(id).getDocument();

    List<FeaturedGroups.PopulatedContentItem> contentItemsListNotModified =
        doc.getContentItemsList();
    Assert.assertFalse(contentItemsListNotModified.isEmpty(), "No content for this feature");

    List<FeaturedGroups.PopulatedContentItem> contentItemsList =
        new ArrayList<>(contentItemsListNotModified);

    // remove 1 - object
    FeaturedGroups.PopulatedContentItem removedItem =
        contentItemsList.get(contentItemsList.size() - 1);
    LogUtils.logInfoMessage("Removed id: " + removedItem);

    // removed 1 from list
    List<FeaturedGroups.PopulatedContentItem> removedCntentItemsList =
        new ArrayList<>(contentItemsList.subList(0, contentItemsList.size() - 1));

    // updated list removed or added
    List<FeaturedGroups.ContentItem> listUpdatedContent = new ArrayList<>();
    // ids were deleted or added
    List<String> listUpdatedIds = new ArrayList<>();

    // removed -1 object
    for (FeaturedGroups.PopulatedContentItem contentItem : removedCntentItemsList) {
      String updateId = contentItem.getContent().getId();

      FeaturedGroups.ContentItem contentUpdated =
          FeaturedGroups.ContentItem.newBuilder()
              .setContent(updateId)
              .setType(contentItem.getType() + "!")
              .setStrategy(contentItem.getStrategy() + "!")
              .setNotes(contentItem.getNotes() + "!")
              .build();

      listUpdatedIds.add(updateId);
      listUpdatedContent.add(contentUpdated);
    }

    FeaturedGroups.FeaturedGroup build =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setId(id)
            .addAllContentItems(listUpdatedContent)
            .build();

    FeaturedGroups.UpdateFieldsRequest request =
        FeaturedGroups.UpdateFieldsRequest.newBuilder()
            .setDocument(build)
            .addAllUpdateFields(List.of("contentItems"))
            .build();

    // Mongo DB for updated ids
    List<Channels> updatedList = channelsUtils.getDocumentsByIds(listUpdatedIds);

    for (int i = 0; i < listUpdatedIds.size(); i++) {
      String idToCheck = listUpdatedIds.get(i);
      Optional<Channels> matchedObject =
          updatedList.stream().filter(e -> e.getId().equals(idToCheck)).findFirst();

      Assert.assertTrue(
          matchedObject.isPresent(), "Object with ID " + idToCheck + " not found in updatedList");
      Assert.assertEquals(
          i + 1,
          matchedObject.get().getFeatured(),
          "Featured value mismatch for object with ID " + idToCheck);
    }

    // revert back removed item
    FeaturedGroups.ContentItem contentWasAdded =
        FeaturedGroups.ContentItem.newBuilder()
            .setContent(removedItem.getContent().getId())
            .setType(removedItem.getType() + "!")
            .setStrategy(removedItem.getStrategy() + "!")
            .setNotes(removedItem.getNotes() + "!")
            .build();

    listUpdatedContent.add(contentWasAdded);

    FeaturedGroups.FeaturedGroup revertedBuild =
        FeaturedGroups.FeaturedGroup.newBuilder()
            .setId(id)
            .addAllContentItems(listUpdatedContent)
            .build();

    FeaturedGroups.UpdateFieldsRequest requestRevert =
        FeaturedGroups.UpdateFieldsRequest.newBuilder()
            .setDocument(revertedBuild)
            .addAllUpdateFields(List.of("contentItems"))
            .build();

    FeaturedGroups.FeaturedGroup revertedDocument =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .updateById(requestRevert)
            .getDocument();
    Assert.assertEquals(
        revertedDocument.getContentItemsList().size(), contentItemsListNotModified.size());

    List<String> listUpdatedIdsReverted =
        listUpdatedContent.stream().map(c -> c.getContent()).collect(Collectors.toList());
    List<Channels> listRevertedChannels = channelsUtils.getDocumentsByIds(listUpdatedIdsReverted);

    for (int i = 0; i < listUpdatedIdsReverted.size(); i++) {
      int finalI = i;
      Channels channels =
          listRevertedChannels.stream()
              .filter(c -> c.getId().equals(listUpdatedIdsReverted.get(finalI)))
              .findFirst()
              .get();
      Assert.assertEquals(i + 1, channels.getFeatured());
    }
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Featured Group not found")
  @Description("Unpublished - invalid id")
  @TmsLink("28500994")
  public void C28500994_TEST() {
    featuredGroupClient.getUnpublished(INVALID_ID);
  }

  @Test
  @Description("Published - happy path")
  @TmsLink("28500995")
  public void C28500995_TEST() {
    FeaturedGroup featured = featuredGroupUtils.getRandomDocument();
    FeaturedGroups.FeaturedGroup publishedClient =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getPublished(featured.getId());

    long nowSeconds = Instant.now().getEpochSecond() / 60;
    long updatedInSeconds = Instant.parse(publishedClient.getUpdatedAt()).getEpochSecond() / 60;
    FeaturedGroup publishedConverted =
        featuredGroupUtils.mapGrpcObjectToPojo(publishedClient, FeaturedGroup.class);
    LogUtils.logInfoMessage(
        "id: " + featured.getId() + ", published: " + publishedClient.getPublished());

    Assert.assertEquals(nowSeconds, updatedInSeconds);
    Assert.assertTrue(publishedClient.getPublished());
    featured.setUpdatedAt(null);
    publishedConverted.setUpdatedAt(null);
    featured.setPublished(true);
    Assert.assertEquals(featured, publishedConverted);
    List<String> channelsFromResponse =
        publishedConverted.getContentItems().stream()
            .map(c -> c.getContent())
            .collect(Collectors.toList());

    List<String> channels =
        publishedConverted.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());
    List<Channels> listChannels = channelsUtils.getDocumentsByIds(channels);

    for (int i = 0; i < channelsFromResponse.size(); i++) {
      int finalI = i;
      Channels chan =
          listChannels.stream()
              .filter(channel -> channel.getId().equals(channelsFromResponse.get(finalI)))
              .findFirst()
              .get();

      Assert.assertEquals(i + 1, chan.getFeatured());
    }
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Featured Group not found")
  @Description("Published - invalid id")
  @TmsLink("28500996")
  public void C28500996_TEST() {
    featuredGroupClient.getPublished(INVALID_ID);
  }

  @Test
  @Description("GetOneByFilter - id")
  @TmsLink("28500997")
  public void C28500997_TEST() {
    FeaturedGroups.GetOneByFilterResponse oneByFilter =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(featuredGroup.getId(), null, "", null);
    FeaturedGroups.GetOneByFilterFeaturedGroup response = oneByFilter.getDocument();

    Assert.assertEquals(featuredGroup.getId(), response.getId());
    Assert.assertEquals(featuredGroup.getName(), response.getName());
    Assert.assertEquals(featuredGroup.getContentItems().size(), response.getContentItemsCount());

    List<String> listChannels =
        featuredGroup.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());
    List<Channels> listDbChannels = channelsUtils.getDocumentsByIds(listChannels);

    featuredGroup
        .getContentItems()
        .forEach(
            content -> {
              FeaturedGroups.GetOneByFilterContentItem responseContent =
                  response.getContentItemsList().stream()
                      .filter(c -> c.getContentId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Channels channel =
                  listDbChannels.stream()
                      .filter(c -> c.getId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Assert.assertTrue(
                  response.getContentItemsList().stream()
                      .anyMatch(c -> c.getContentId().equals(content.getContent())));
              Assert.assertEquals(responseContent.getPublished(), channel.getPublished());
            });
  }

  @Test
  @Description("GetOneByFilter - filter by name")
  @TmsLink("28500998")
  public void C28500998_TEST() {
    Filter filter =
        Filter.newBuilder()
            .setField("name")
            .setValue(featuredGroup.getName())
            .setType("string")
            .build();
    FeaturedGroups.GetOneByFilterResponse oneByFilter =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(featuredGroup.getId(), null, "", List.of(filter));
    FeaturedGroups.GetOneByFilterFeaturedGroup response = oneByFilter.getDocument();

    Assert.assertEquals(featuredGroup.getId(), response.getId());
    Assert.assertEquals(featuredGroup.getName(), response.getName());
    Assert.assertEquals(featuredGroup.getContentItems().size(), response.getContentItemsCount());

    List<String> listChannels =
        featuredGroup.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());
    List<Channels> listDbChannels = channelsUtils.getDocumentsByIds(listChannels);

    featuredGroup
        .getContentItems()
        .forEach(
            content -> {
              FeaturedGroups.GetOneByFilterContentItem responseContent =
                  response.getContentItemsList().stream()
                      .filter(c -> c.getContentId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Channels channel =
                  listDbChannels.stream()
                      .filter(c -> c.getId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Assert.assertTrue(
                  response.getContentItemsList().stream()
                      .anyMatch(c -> c.getContentId().equals(content.getContent())));
              Assert.assertEquals(responseContent.getPublished(), channel.getPublished());
            });
  }

  @Test
  @Description("GetOneByFilter - valid min start date")
  @TmsLink("28500999")
  public void C28500999_TEST() {
    FeaturedGroups.GetOneByFilterResponse oneByFilter =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(
                featuredGroup.getId(),
                null,
                String.valueOf(featuredGroup.getStart().getTime()),
                null);
    FeaturedGroups.GetOneByFilterFeaturedGroup response = oneByFilter.getDocument();

    Assert.assertEquals(featuredGroup.getId(), response.getId());
    Assert.assertEquals(featuredGroup.getName(), response.getName());
    Assert.assertEquals(featuredGroup.getContentItems().size(), response.getContentItemsCount());

    List<String> listChannels =
        featuredGroup.getContentItems().stream()
            .map(ContentItems::getContent)
            .collect(Collectors.toList());
    List<Channels> listDbChannels = channelsUtils.getDocumentsByIds(listChannels);

    featuredGroup
        .getContentItems()
        .forEach(
            content -> {
              FeaturedGroups.GetOneByFilterContentItem responseContent =
                  response.getContentItemsList().stream()
                      .filter(c -> c.getContentId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Channels channel =
                  listDbChannels.stream()
                      .filter(c -> c.getId().equals(content.getContent()))
                      .findFirst()
                      .get();

              Assert.assertTrue(
                  response.getContentItemsList().stream()
                      .anyMatch(c -> c.getContentId().equals(content.getContent())));
              Assert.assertEquals(responseContent.getPublished(), channel.getPublished());
            });
  }

  @Test
  @Description("GetOneByFilter - exclude ids")
  @TmsLink("28501003")
  public void C28501003_TEST() {
    List<FeaturedGroup> featuredGroups = featuredGroupUtils.getDocuments(150);
    List<String> listAllIds =
        featuredGroups.stream().map(FeaturedGroup::getId).collect(Collectors.toList());
    Assert.assertEquals(featuredGroups.size(), listAllIds.size());
    List<String> listIds = listAllIds.subList(0, 1);

    FeaturedGroups.GetOneByFilterFeaturedGroup response =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(
                "",
                listIds,
                String.valueOf(featuredGroups.get(0).getStart().toInstant().getEpochSecond()),
                null)
            .getDocument();

    boolean idInResponse = listIds.stream().noneMatch(id -> id.equals(response.getId()));
    Assert.assertTrue(idInResponse);

    // create removed data
    FeaturedGroups.CreateRequest createRequest =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
            .getNewFeaturedGroup(featuredGroup, null, true);
    new FeaturedGroupClient(grpcChannelManager.getChannel(), true).create(createRequest);
  }

  @Test
  @Description("GetOneByFilter - exclude and filter")
  @TmsLink("28501002")
  public void C28501002_TEST() {
    List<FeaturedGroup> featuredGroups = featuredGroupUtils.getDocuments(150);
    FeaturedGroup feature = featuredGroups.get(0);

    List<String> listAllIds =
        featuredGroups.stream().map(FeaturedGroup::getId).collect(Collectors.toList());
    Assert.assertEquals(featuredGroups.size(), listAllIds.size());
    List<String> listIds = listAllIds.subList(1, 2);

    FeaturedGroups.Filter filter =
        FeaturedGroups.Filter.newBuilder()
            .setField("name")
            .setValue(feature.getName())
            .setType("string")
            .build();

    FeaturedGroups.GetOneByFilterFeaturedGroup response =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(
                "", listIds, String.valueOf(feature.getStart().getTime()), List.of(filter))
            .getDocument();

    boolean idInResponse = listIds.stream().noneMatch(id -> id.equals(response.getId()));

    Assert.assertTrue(idInResponse);
    Assert.assertEquals(feature.getName(), response.getName());

    // create removed data
    FeaturedGroups.CreateRequest createRequest =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), true)
            .getNewFeaturedGroup(featuredGroup, null, true);
    new FeaturedGroupClient(grpcChannelManager.getChannel(), true).create(createRequest);
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Featured Group not found")
  @Description("GetOneByFilter - exclude and filter negative")
  @TmsLink("28501004")
  public void C28501004_TEST() {
    String name = new Faker().name().username();
    List<FeaturedGroup> featuredGroups = featuredGroupUtils.getDocuments(150);
    FeaturedGroup feature = featuredGroups.get(0);

    List<String> listIds =
        featuredGroups.stream().map(FeaturedGroup::getId).collect(Collectors.toList());
    Assert.assertEquals(featuredGroups.size(), listIds.size());

    FeaturedGroups.Filter filter =
        FeaturedGroups.Filter.newBuilder()
            .setField("name")
            .setValue(name)
            .setType("string")
            .build();

    featuredGroupClient
        .getOneByFilter("", listIds, String.valueOf(feature.getStart().getTime()), List.of(filter))
        .getDocument();
  }

  @Test
  @Description("GetOneByFilter - published")
  @TmsLink("28501001")
  public void C28501001_TEST() {
    FeaturedGroup featuredGroup = featuredGroupUtils.getRandomDocument();

    FeaturedGroups.GetOneByFilterResponse oneByFilter =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getOneByFilter(
                featuredGroup.getId(),
                null,
                String.valueOf(featuredGroup.getStart().getTime()),
                null);

    oneByFilter
        .getDocument()
        .getContentItemsList()
        .forEach(
            content -> {
              Channels ch = channelsUtils.getDocumentById(content.getContentId());
              Assert.assertEquals(
                  content.getPublished(),
                  ch != null && ch.getPublished(),
                  "published mismatch for channel " + content.getContentId());
            });
  }

  @Test(
      expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Featured Group not found")
  @Description("GetOneByFilter - after valid min start date")
  @TmsLink("28501000")
  public void C28501000_TEST() {
    new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
        .getOneByFilter(
            featuredGroup.getId(),
            null,
            String.valueOf(featuredGroup.getStart().getTime() + 1),
            null);
  }

  // TO DO need to check the test data
  @Test(enabled = false)
  @Description("GetAllPaged - concurrentStartGroups")
  @TmsLink("28501006")
  public void C28501006_TEST() {
    int limit = 2;
    List<FeaturedGroups.GetAllPagedSort> sort =
        List.of(new FeaturedGroupClient(grpcChannelManager.getChannel(), false).getSort("name", 1));

    FeaturedGroups.GetAllPagedResponse featuredAllPaged =
        new FeaturedGroupClient(grpcChannelManager.getChannel(), false)
            .getAllPaged(limit, 0, sort, null, true);
    Assert.assertEquals(limit, featuredAllPaged.getDocumentsList().size());
    Assert.assertEquals(limit, featuredAllPaged.getMetadata().getTotalItems());

    for (FeaturedGroups.GetAllPagedFeaturedGroup getAll : featuredAllPaged.getDocumentsList()) {
      String start = getAll.getStart();
      List<FeaturedGroup> listFeaturedStart = featuredGroupUtils.getListFeaturedStart(start);

      List<FeaturedGroup> filteredGroups =
          listFeaturedStart.stream()
              .filter(
                  f ->
                      f.getActiveRegion().equals(getAll.getActiveRegion())
                          && f.getName().equals(getAll.getName())
                          && !f.getId().equals(getAll.getId()))
              .collect(Collectors.toList());

      Assert.assertEquals(getAll.getConcurrentStartGroupsCount(), filteredGroups.size());

      for (FeaturedGroup filteredGroup : filteredGroups) {
        FeaturedGroups.ConcurrentStartGroup concurrentStartGroup =
            getAll.getConcurrentStartGroupsList().stream()
                .filter(c -> c.getId().equals(filteredGroup.getId()))
                .findFirst()
                .get();

        Assert.assertEquals(concurrentStartGroup.getName(), filteredGroup.getName());
      }
    }
  }

  @Test(dataProvider = "sort-values")
  @Description("GetAllPaged - sort value")
  @TmsLink("28501005")
  public void C28501005_TEST(int sortValue) {
    FeaturedGroupClient client = new FeaturedGroupClient(grpcChannelManager.getChannel(), true);
    List<FeaturedGroups.GetAllPagedSort> sort = List.of(client.getSort("name", sortValue));

    String testStart = Instant.now().toString();

    FeaturedGroups.Filter filter =
        FeaturedGroups.Filter.newBuilder()
            .setField("start")
            .setValue(testStart)
            .setType("string")
            .build();

    // create 5 featured groups and sort them by name. No db data to be used
    FeaturedGroups.FeaturedGroup aDalTest = client.getTestFeatureGroup("AdalTest", testStart);
    FeaturedGroups.FeaturedGroup bDalTest = client.getTestFeatureGroup("BdalTest", testStart);
    FeaturedGroups.FeaturedGroup cDalTest = client.getTestFeatureGroup("cdalTest", testStart);
    FeaturedGroups.FeaturedGroup dDalTest = client.getTestFeatureGroup("DdalTest", testStart);
    FeaturedGroups.FeaturedGroup eDalTest = client.getTestFeatureGroup("edalTest", testStart);

    List<String> listCreatedIds =
        List.of(
            aDalTest.getId(),
            bDalTest.getId(),
            cDalTest.getId(),
            dDalTest.getId(),
            eDalTest.getId());

    FeaturedGroups.GetAllPagedResponse featuredAllPaged =
        client.getAllPaged(null, 0, sort, List.of(filter), true);

    Assert.assertEquals(listCreatedIds.size(), featuredAllPaged.getDocumentsList().size());

    List<String> responseNameList =
        featuredAllPaged.getDocumentsList().stream()
            .map(FeaturedGroups.GetAllPagedFeaturedGroup::getName)
            .collect(Collectors.toList());

    List<String> sortedName = new ArrayList<>(responseNameList);

    if (sortValue == 1) Collections.sort(sortedName, new CommonUtils.NumericStringComparator());
    else
      Collections.sort(
          sortedName, Collections.reverseOrder(new CommonUtils.NumericStringComparator()));

    Assert.assertEquals(sortedName, responseNameList);

    Assert.assertEquals(
        listCreatedIds.size(), client.deleteByIds(listCreatedIds).getDeletedCount());
  }
}
