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

import io.grpc.StatusRuntimeException;
import io.qameta.allure.Description;
import io.qameta.allure.Issue;
import io.qameta.allure.TmsLink;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
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.placeholder.Placeholder;
import tv.pluto.grpc.placeholder.PlaceholderClient;
import tv.pluto.grpc.placeholder.PlaceholderRequest;
import tv.pluto.mongo.entities.placeholder.BumperSet;
import tv.pluto.mongo.entities.placeholder.Clip;
import tv.pluto.mongo.entities.placeholder.Country;
import tv.pluto.mongo.entities.placeholder.Source;
import tv.pluto.mongo.utils.PlaceholderUtils;
import tv.pluto.mongo.utils.equals.PlaceholderEqualsUtils;

public class PlaceholderTestSuite extends BaseTest {
  private PlaceholderClient placeholderClient;
  private PlaceholderUtils placeholderUtils;

  @BeforeClass(alwaysRun = true)
  private void setUp() {
    placeholderUtils = new PlaceholderUtils();

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

  @Test
  @Description("Return only filler clips - GetPlaceholdersRequest")
  @TmsLink("28501195")
  public void C28501195_TEST() {
    PlaceholderRequest request = new PlaceholderRequest();
    request.setReturnFillerClips(true);

    Map<String, Placeholder> mongoPlaceholdersMap =
        placeholderUtils.getPlaceholderSets(request).getPlaceholders();

    Map<String, ?> mappedPlaceholdersMap =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getPlaceholders(request).getPlaceholdersMap(), Placeholder.class);

    Assert.assertEquals(mongoPlaceholdersMap, mappedPlaceholdersMap);
  }

  @Test
  @Description("Return only error clips - GetPlaceholdersRequest")
  @TmsLink("28501196")
  public void C28501196_TEST() {
    PlaceholderRequest request = new PlaceholderRequest();
    request.setReturnErrorClip(true);

    Map<String, Placeholder> mongoPlaceholdersMap =
        placeholderUtils.getPlaceholderSets(request).getPlaceholders();

    Map<String, ?> mappedPlaceholdersMap =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getPlaceholders(request).getPlaceholdersMap(), Placeholder.class);

    for (String key : mappedPlaceholdersMap.keySet()) {
      if (mongoPlaceholdersMap.containsKey(key)) {
        mongoPlaceholdersMap
            .get(key)
            .setError(((Placeholder) mappedPlaceholdersMap.get(key)).getError());
      }
    }

    Assert.assertEquals(mongoPlaceholdersMap, mappedPlaceholdersMap);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp =
          "NOT_FOUND: Placeholder Sets for requested input not found.")
  @Description("Invalid request - GetPlaceholdersRequest")
  @TmsLink("28501197")
  public void C28501197_TEST() {
    PlaceholderRequest request = new PlaceholderRequest();
    request.setReturnBumperClips(true);
    request.setBumperDuration(30);
    request.setMarketingRegion("us");

    Map<String, Placeholder> mongoPlaceholdersMap =
        placeholderUtils.getPlaceholderSets(request).getPlaceholders();

    Map<String, ?> mappedPlaceholdersMap =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getPlaceholders(request).getPlaceholdersMap(), Placeholder.class);

    Assert.assertEquals(mongoPlaceholdersMap, mappedPlaceholdersMap);
  }

  @Test(enabled = false)
  @Issue("ARCH-2434")
  @Description("Test - GetComplexBumperSets")
  @TmsLink("28501198")
  public void C28501198_TEST() {
    PlaceholderEqualsUtils placeholderEqualsUtils = new PlaceholderEqualsUtils();

    Map<String, Country> mongoComplexBumperSets = placeholderUtils.getComplexBumperSets();
    Map<String, tv.pluto.ip.dal.placeholder.Placeholder.Country> grpcComplexBumperSets =
        placeholderClient.getComplexBumperSetsResponse().getCountriesMap();

    placeholderEqualsUtils.verifyComplexBumperSetsEquals(
        mongoComplexBumperSets, grpcComplexBumperSets);
  }

  @Test
  @Description("GetComplexBumperSets ident_card_bumper")
  @TmsLink("28501205")
  public void C28501205_TEST() {
    String identCardBumper = "ident_card_bumper";

    Map<String, Country> mongoComplexBumperSets = placeholderUtils.getComplexBumperSets();
    Map<String, tv.pluto.ip.dal.placeholder.Placeholder.Country> grpcComplexBumperSets =
        placeholderClient.getComplexBumperSetsResponse().getCountriesMap();

    List<Clip> preBumpersDB =
        mongoComplexBumperSets.entrySet().stream()
            .flatMap(entry -> entry.getValue().getBumperSets().values().stream())
            .flatMap(bumperSets -> bumperSets.getPreBumpers().stream())
            .filter(clip -> clip.getTags().contains(identCardBumper))
            .collect(Collectors.toList());

    List<Clip> postBumpersDB =
        mongoComplexBumperSets.entrySet().stream()
            .flatMap(entry -> entry.getValue().getBumperSets().values().stream())
            .flatMap(bumperSets -> bumperSets.getPostBumpers().stream())
            .filter(clip -> clip.getTags().contains(identCardBumper))
            .collect(Collectors.toList());

    List<tv.pluto.ip.dal.placeholder.Placeholder.Clip> preBumpersGrpc =
        grpcComplexBumperSets.entrySet().stream()
            .flatMap(entry -> entry.getValue().getBumperSetsMap().values().stream())
            .flatMap(bumperSets -> bumperSets.getPreBumpersList().stream())
            .filter(clip -> clip.getTagsList().contains(identCardBumper))
            .collect(Collectors.toList());

    List<tv.pluto.ip.dal.placeholder.Placeholder.Clip> postBumpersGrpc =
        grpcComplexBumperSets.entrySet().stream()
            .flatMap(entry -> entry.getValue().getBumperSetsMap().values().stream())
            .flatMap(bumperSets -> bumperSets.getPostBumpersList().stream())
            .filter(clip -> clip.getTagsList().contains(identCardBumper))
            .collect(Collectors.toList());

    List<Clip> grpcPreBumper = placeholderUtils.mapGrpcObjectsToPojo(preBumpersGrpc, Clip.class);
    List<Clip> grpcPostBumper = placeholderUtils.mapGrpcObjectsToPojo(postBumpersGrpc, Clip.class);

    grpcPreBumper.sort(Comparator.comparing(Clip::getId));
    grpcPostBumper.sort(Comparator.comparing(Clip::getId));
    preBumpersDB.sort(Comparator.comparing(Clip::getId));
    postBumpersDB.sort(Comparator.comparing(Clip::getId));

    Assert.assertTrue(preBumpersDB.size() > 0 || postBumpersDB.size() > 0);
    Assert.assertEquals(grpcPreBumper, preBumpersDB);
    Assert.assertEquals(grpcPostBumper, postBumpersDB);
  }

  @Test
  @Description("Get bumper sets without duration - GetBumperSets")
  @TmsLink("28501199")
  public void C28501199_TEST() {
    Map<String, BumperSet> mongoBumperSets =
        placeholderUtils.getBumperSets(
            null, Arrays.asList("country_uk_1", "plutotv_pre_bumper", "plutotv_post_bumper"));

    Map<String, ?> mappedBumperSets =
        placeholderUtils.mapMapToPojo(
            placeholderClient
                .getBumperSets(
                    null,
                    Arrays.asList("country_uk_1", "plutotv_pre_bumper", "plutotv_post_bumper"))
                .getBumperSetsMap(),
            BumperSet.class);

    // data issue
    Assert.assertNotNull(mappedBumperSets.get("country_fi"));
    mongoBumperSets.remove("country_fi");
    mappedBumperSets.remove("country_fi");

    Assert.assertEquals(mongoBumperSets, mappedBumperSets);
  }

  @Test
  @Description("Get bumper sets without tags - GetBumperSets")
  @TmsLink("28501200")
  public void C28501200_TEST() {
    Map<String, BumperSet> mongoBumperSets =
        placeholderUtils.getBumperSets(5.0, Collections.emptyList());

    Map<String, ?> mappedBumperSets =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getBumperSets(5, Collections.emptyList()).getBumperSetsMap(),
            BumperSet.class);

    // data issue
    Assert.assertNotNull(mappedBumperSets.get("country_fi"));
    mongoBumperSets.remove("country_fi");
    mappedBumperSets.remove("country_fi");

    Assert.assertEquals(mongoBumperSets, mappedBumperSets);
  }

  @Test
  @Description("Get bumper sets with duration and tags - GetBumperSets")
  @TmsLink("28501201")
  public void C28501201_TEST() {
    Map<String, BumperSet> mongoBumperSets =
        placeholderUtils.getBumperSets(
            5.0, Arrays.asList("country_uk_1", "plutotv_pre_bumper", "plutotv_post_bumper"));

    Map<String, ?> mappedBumperSets =
        placeholderUtils.mapMapToPojo(
            placeholderClient
                .getBumperSets(
                    5, Arrays.asList("country_uk_1", "plutotv_pre_bumper", "plutotv_post_bumper"))
                .getBumperSetsMap(),
            BumperSet.class);

    // data issue
    Assert.assertNotNull(mappedBumperSets.get("country_fi"));
    mongoBumperSets.remove("country_fi");
    mappedBumperSets.remove("country_fi");

    Assert.assertEquals(mongoBumperSets, mappedBumperSets);
  }

  @Test
  @Description("Get bumper sets without duration and tags - GetBumperSets")
  @TmsLink("28501202")
  public void C28501202_TEST() {
    Map<String, BumperSet> mongoBumperSets =
        placeholderUtils.getBumperSets(null, Collections.emptyList());

    Map<String, ?> mappedBumperSets =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getBumperSets(null, Collections.emptyList()).getBumperSetsMap(),
            BumperSet.class);

    // data issue
    Assert.assertNotNull(mappedBumperSets.get("country_fi"));
    mongoBumperSets.remove("country_fi");
    mappedBumperSets.remove("country_fi");

    Assert.assertEquals(mongoBumperSets, mappedBumperSets);
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Bumper sets for requested input not found.")
  @Description("Invalid request - GetBumperSets")
  @TmsLink("28501203")
  public void C28501203_TEST() {
    placeholderClient
        .getBumperSets(5, Collections.singletonList("country_uk_1"))
        .getBumperSetsMap();
  }

  @Test
  @Description("Verifying that Placeholder Clip.sources have 2 types: HLS and DASH")
  @TmsLink("28501204")
  public void C28501204_TEST() {
    PlaceholderRequest request = new PlaceholderRequest();
    request.setReturnFillerClips(true);

    Map<String, Placeholder> mongoPlaceholdersMap =
        placeholderUtils.getPlaceholderSets(request).getPlaceholders();

    Map<String, ?> mappedPlaceholdersMap =
        placeholderUtils.mapMapToPojo(
            placeholderClient.getPlaceholders(request).getPlaceholdersMap(), Placeholder.class);

    Assert.assertEquals(mongoPlaceholdersMap, mappedPlaceholdersMap);

    mongoPlaceholdersMap
        .values()
        .forEach(
            placeholder ->
                placeholder
                    .getFillers()
                    .forEach(
                        filler -> {
                          List<Source> sources = filler.getSources();
                          Assert.assertTrue(
                              sources.stream().anyMatch(source -> source.getType().equals("HLS")));
                          Assert.assertTrue(
                              sources.stream().anyMatch(source -> source.getType().equals("DASH")));
                        }));
  }

  @Test(
      expectedExceptions = StatusRuntimeException.class,
      expectedExceptionsMessageRegExp = "NOT_FOUND: Bumper sets for requested input not found.")
  @Description("Get bumper sets not found for pluto - GetBumperSets")
  @TmsLink("29221559")
  public void C29221559_TEST() {
    placeholderClient
        .getBumperSets(5, Arrays.asList("pluto_pre_bumper", "pluto_post_bumper"))
        .getBumperSetsMap();
  }
}
