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

import static tv.pluto.ip.dal.clip.Clips.CFeedsSyncAllIdsRequest;
import static tv.pluto.ip.dal.clip.Clips.CFeedsSyncDocumentsRequest;
import static tv.pluto.ip.dal.clip.Clips.Clip;
import static tv.pluto.ip.dal.clip.Clips.CreateRequest;
import static tv.pluto.ip.dal.clip.Clips.CreateResponse;
import static tv.pluto.ip.dal.clip.Clips.DeleteByIdRequest;
import static tv.pluto.ip.dal.clip.Clips.DeleteByIdResponse;
import static tv.pluto.ip.dal.clip.Clips.DeleteByIdsRequest;
import static tv.pluto.ip.dal.clip.Clips.DeleteByIdsResponse;
import static tv.pluto.ip.dal.clip.Clips.GetBackfillClipsRequest;
import static tv.pluto.ip.dal.clip.Clips.GetBackfillClipsResponse;
import static tv.pluto.ip.dal.clip.Clips.GetByIdRequest;
import static tv.pluto.ip.dal.clip.Clips.GetByIdResponse;
import static tv.pluto.ip.dal.clip.Clips.GetByIdsRequest;
import static tv.pluto.ip.dal.clip.Clips.GetByIdsResponse;
import static tv.pluto.ip.dal.clip.Clips.GetDocumentsUpdatedBetweenDatesRequest;
import static tv.pluto.ip.dal.clip.Clips.GetErrorClipsRequest;
import static tv.pluto.ip.dal.clip.Clips.GetErrorClipsResponse;
import static tv.pluto.ip.dal.clip.Clips.UpdateByIdReturnUpdatedRequest;
import static tv.pluto.ip.dal.clip.Clips.UpdateByIdReturnUpdatedResponse;
import static tv.pluto.ip.dal.clip.Clips.UpdateContentMamUniqueIdsByIdsRequest;
import static tv.pluto.ip.dal.clip.Clips.UpdateContentMamUniqueIdsByIdsResponse;

import com.plutotv.test.lib.LogUtils;
import io.grpc.Channel;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;
import net.datafaker.Faker;
import org.testng.Assert;
import tv.pluto.grpc.GenericGrpcClient;
import tv.pluto.ip.dal.clip.ClipManagerGrpc;
import tv.pluto.ip.dal.clip.Clips;
import tv.pluto.mongo.entities.common.ObjectIdContentIdSet;
import tv.pluto.utils.CommonUtils;

/** Class represents gRPC client for <b>clips.proto</b> file */
public class ClipsClient extends GenericGrpcClient {

  private static final Logger logger = Logger.getLogger(ClipsClient.class.getName());
  private Clips.GetAllPagedRequest.Builder getAllPagedBuilder =
      Clips.GetAllPagedRequest.newBuilder();

  private ClipManagerGrpc.ClipManagerBlockingStub blockingStub;

  public ClipsClient(Channel channel, boolean auth) {
    if (auth) {
      blockingStub = ClipManagerGrpc.newBlockingStub(channel);
      blockingStub = blockingStub.withInterceptors(CLIENT_INTERCEPTOR_AUTH);
    } else {
      blockingStub = ClipManagerGrpc.newBlockingStub(channel);
      blockingStub = blockingStub.withInterceptors(CLIENT_INTERCEPTOR);
    }
    this.getDocumentsUpdatedBetweenDatesRequestBuilder =
        GetDocumentsUpdatedBetweenDatesRequest.newBuilder();
    this.getCFeedsAllIdsBuilder = CFeedsSyncAllIdsRequest.newBuilder();
    this.getCFeedsSyncDocumentsBuilder = CFeedsSyncDocumentsRequest.newBuilder();
  }

  /**
   * Method represents gRPC method GetClipById from <b>clips.proto</b> file
   *
   * @param clipId id of the clip
   */
  public GetByIdResponse getById(String clipId) {
    logger.info("Getting clip for id: " + clipId + " ...");
    GetByIdRequest request = GetByIdRequest.newBuilder().setId(clipId).build();

    return blockingStub.getById(request);
  }

  public GetByIdsResponse getByIds(List<String> clipsIds) {
    logger.info("Getting clips for ids: " + clipsIds + " ...");

    GetByIdsRequest request = GetByIdsRequest.newBuilder().addAllIds(clipsIds).build();
    return blockingStub.getByIds(request);
  }

  public GetByIdsResponse getByIds(List<String> clipsIds, List<String> projections) {
    logger.info("Getting clips for ids: " + clipsIds + " ...");

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(clipsIds).addAllProjection(projections).build();
    return blockingStub.getByIds(request);
  }

  public GetByIdsResponse getByIdsWithFilters(
      List<String> clipsIds, List<tv.pluto.ip.dal.clip.Clips.Filter> filters) {
    logger.info("Getting clips for ids: " + clipsIds + " ...");

    GetByIdsRequest request =
        GetByIdsRequest.newBuilder().addAllIds(clipsIds).addAllFilters(filters).build();
    return blockingStub.getByIds(request);
  }

  /**
   * Method represents gRPC method GetClipsByIds from <b>clips.proto</b> file
   *
   * @param clipsIds List of clips ids to search
   */
  public Clips.GetClipsByIdsResponse getClipsByIds(List<String> clipsIds) {
    logger.info("Getting clips for ids: " + clipsIds + " ...");

    Clips.GetClipsByIdsRequest request =
        Clips.GetClipsByIdsRequest.newBuilder().addAllIds(clipsIds).build();
    return blockingStub.getClipsByIds(request);
  }

  /**
   * Method represents gRPC method updateByIdReturnUpdated from <b>clips.proto</b> file
   *
   * @param id - ID of clip for update
   * @param clip - Clip objects with set fields for update
   * @param updateFields - List of fields which will be updated
   * @return Clip with updated fields
   */
  public UpdateByIdReturnUpdatedResponse updateByIdReturnUpdated(
      String id, Clip clip, List<String> updateFields) {
    LogUtils.logInfoMessage(
        "Update clip with ID="
            + id
            + "\nClip object "
            + clip
            + "\n update fields list "
            + updateFields);

    UpdateByIdReturnUpdatedRequest request =
        UpdateByIdReturnUpdatedRequest.newBuilder()
            .setId(id)
            .setDocument(clip)
            .addAllUpdateFields(updateFields)
            .build();

    return blockingStub.updateByIdReturnUpdated(request);
  }

  /**
   * Method represents gRPC method GetBackfillClips from <b>clips.proto</b> file
   *
   * @return GetBackfillClipsResponse object
   */
  public GetBackfillClipsResponse getBackfillClipsResponse() {
    LogUtils.logInfoMessage("Getting backfill clips");

    return blockingStub.getBackfillClips(GetBackfillClipsRequest.newBuilder().build());
  }

  /**
   * Method represents gRPC method GetErrorClips from <b>clips.proto</b> file
   *
   * @return GetErrorClipsResponse object
   */
  public GetErrorClipsResponse getErrorClips() {
    LogUtils.logInfoMessage("Getting backfill clips");

    return blockingStub.getErrorClips(GetErrorClipsRequest.newBuilder().build());
  }

  public UpdateContentMamUniqueIdsByIdsResponse updateContentMamUniqueIdsByIds(
      List<ObjectIdContentIdSet> objectIdContentIdSets) {
    LogUtils.logInfoMessage("Updating clips contentUUID for " + objectIdContentIdSets);

    UpdateContentMamUniqueIdsByIdsRequest.Builder builder =
        UpdateContentMamUniqueIdsByIdsRequest.newBuilder();

    objectIdContentIdSets.forEach(
        value ->
            builder.addObjectIdContentIdSets(
                Clips.ObjectIdContentIdSet.newBuilder()
                    .setId(value.getId())
                    .setContentUUID(value.getContentUUID())
                    .build()));

    return blockingStub.updateContentMamUniqueIdsByIds(builder.build());
  }

  public CreateResponse create(Clips.Clip testClip) {
    Clips.Clip clip = testClip.toBuilder().setId("").build();
    CreateRequest request = CreateRequest.newBuilder().setDocument(clip).build();

    return blockingStub.create(request);
  }

  public DeleteByIdResponse deleteById(String id) {
    DeleteByIdRequest request = DeleteByIdRequest.newBuilder().setId(id).build();
    LogUtils.logInfoMessage("Deleting clip id: " + id);
    return blockingStub.deleteById(request);
  }

  public void deleteByIdWithAssertion(String id) {
    DeleteByIdRequest request = DeleteByIdRequest.newBuilder().setId(id).build();
    LogUtils.logInfoMessage("Deleting clip id: " + id);
    Assert.assertEquals(1, blockingStub.deleteById(request).getDeletedCount());
  }

  public DeleteByIdsResponse deleteByIds(List<String> ids) {
    DeleteByIdsRequest request = DeleteByIdsRequest.newBuilder().addAllIds(ids).build();

    return blockingStub.deleteByIds(request);
  }

  public Iterator<Clip> getAll(String region) {
    Clips.GetAllRequest getAllRequest = Clips.GetAllRequest.newBuilder().setRegion(region).build();
    return blockingStub.getAll(getAllRequest);
  }

  public Clips.UpdateFieldsResponse updateClipsName(String id, String name) {
    Clip.Builder clip = Clip.newBuilder().setName(name).setId(id);

    Clips.UpdateFieldsRequest request =
        Clips.UpdateFieldsRequest.newBuilder()
            .setId(id)
            .setDocument(clip)
            .addAllUpdateFields(Collections.singletonList("name"))
            .build();

    return blockingStub.updateFields(request);
  }

  public Clips.UpdateFieldsResponse updateClipFields(String id, Clip clip, List<String> fields) {
    Clips.UpdateFieldsRequest request =
        Clips.UpdateFieldsRequest.newBuilder()
            .setId(id)
            .setDocument(clip)
            .addAllUpdateFields(fields)
            .build();

    return blockingStub.updateFields(request);
  }

  public Clips.Highlight.Builder getHighlightsClipBuilder(String id) {
    tv.pluto.ip.dal.clip.Clips.HighlightMedia medias =
        tv.pluto.ip.dal.clip.Clips.HighlightMedia.newBuilder()
            .setType("JPG")
            .setMaxWidth(10)
            .setMaxHeight(100)
            .setUrl("https://siloh-ns1.pluto.tv")
            .build();

    Clips.HighlightOutput HighlightOutputBuilder =
        Clips.HighlightOutput.newBuilder()
            .addAllMedias(List.of(medias))
            .setId(id)
            .setStartOffsetMs(5000)
            .setEndOffsetMs(35000)
            .setMarkupId(id)
            .build();

    return tv.pluto.ip.dal.clip.Clips.Highlight.newBuilder()
        .addAllOutputs(List.of(HighlightOutputBuilder));
  }

  public Clips.Markup getMarkupBuilderFromHighlight(Clips.HighlightOutput output) {
    return Clips.Markup.newBuilder()
        .setId(output.getId())
        .setObjectId(output.getId())
        .setType("highlight")
        .setStart(output.getStartOffsetMs())
        .setEnd(output.getEndOffsetMs())
        .build();
  }

  public Iterator<Clips.Id> getClipsIdsFromCFeeds(boolean isPublished) {
    CFeedsSyncAllIdsRequest cFeedsRequest =
        CFeedsSyncAllIdsRequest.newBuilder().setPublished(isPublished).build();
    return blockingStub.cFeedsSyncAllIds(cFeedsRequest);
  }

  public Clips.GetComScoreByIdResponse getComScoreById(String id) {
    Clips.Id request = Clips.Id.newBuilder().setId(id).build();
    return blockingStub.getComScoreById(request);
  }

  public Clips.Filter getFilter(String field, String value, String type) {
    return Clips.Filter.newBuilder().setField(field).setValue(value).setType(type).build();
  }

  public CreateResponse createLanguageOverridesTranscode() {
    CreateRequest request = CreateRequest.newBuilder().setDocument(getClipGrpcToCreate()).build();
    return blockingStub.create(request);
  }

  public Clip getClipGrpcToCreate() {
    Clips.DiscreteAudio discreteAudio =
        Clips.DiscreteAudio.newBuilder()
            .setAudioType("audio")
            .setLanguage("en")
            .setUri("uri")
            .build();

    Clips.Highlight.Builder highlightBuild =
        getHighlightsClipBuilder(CommonUtils.generateRandomObjectId());

    Clips.HighlightOutput outputs = highlightBuild.getOutputs(0);
    Assert.assertNotNull(outputs, "Highlight output is null");

    Clips.Markup markup = getMarkupBuilderFromHighlight(outputs);

    Clips.Window windows =
        Clips.Window.newBuilder().setCurrentScreenings(3).setScreenings(5).build();

    Clips.AvailabilityWindows availabilityWindows =
        Clips.AvailabilityWindows.newBuilder().addAVOD(windows).addLinear(windows).build();

    Clips.DistributeAs distribution =
        Clips.DistributeAs.newBuilder()
            .setTVOD(true)
            .setSVOD(true)
            .setAVOD(true)
            .setLinear(true)
            .build();

    Clips.RegionOverrides regionOverrides =
        Clips.RegionOverrides.newBuilder()
            .setBreakpoints("1920x1080")
            .setAvailabilityWindows(availabilityWindows)
            .setDistributeAs(distribution)
            .build();

    Clips.LanguageOverrides languageOverrides =
        Clips.LanguageOverrides.newBuilder()
            .setName("name")
            .setSummary("summary")
            .setDescription("description")
            .setTile(Clips.Tile.newBuilder().setPath("path").build())
            .setBreakpoints("1920x1080")
            .addAllTags(List.of("tag1", "tag2"))
            .build();

    tv.pluto.ip.dal.clip.Clips.Source source =
        tv.pluto.ip.dal.clip.Clips.Source.newBuilder()
            .setType("HLS")
            .setEncryption("ClearKeyFile")
            .setFile("https://siloh.pluto.tv")
            .build();

    tv.pluto.ip.dal.clip.Clips.TranscodeSource transSource =
        tv.pluto.ip.dal.clip.Clips.TranscodeSource.newBuilder()
            .setType("HLS")
            .setUrl("http://content.pluto.tv")
            .build();

    tv.pluto.ip.dal.clip.Clips.TranscodeProfile transProfile =
        tv.pluto.ip.dal.clip.Clips.TranscodeProfile.newBuilder().setName("nameProfile").build();

    Clips.TranscodeObject transcode =
        Clips.TranscodeObject.newBuilder()
            .setState("ready")
            .setUpdatedAt("2024-10-25T16:18:11.580Z")
            .setJobId("1")
            .setError("error")
            .setCode("code")
            .setSource(transSource)
            .setProfile(transProfile)
            .build();

    String tag = new Faker().word().toString();

    return Clip.newBuilder()
        .setCode("code")
        .addTags(tag)
        .setName("name")
        .setSummary("sumarry")
        .setDescription("description")
        .setDuration(90)
        .setUrl("https://siloh-ns1.pluto.tv")
        .setProvider("jwplatform")
        .addAllSources(List.of(source))
        .setId("")
        .putRegionOverrides("en", regionOverrides)
        .putRegionOverrides("es", regionOverrides)
        .putLanguageOverrides("en", languageOverrides)
        .putLanguageOverrides("es", languageOverrides)
        .setActiveRegion("ZA")
        .setTranscode(transcode)
        .setHighlight(highlightBuild)
        .addMarkups(markup)
        .addAllDiscreteAudio(List.of(discreteAudio, discreteAudio))
        .setPublished(true)
        .build();
  }

  public tv.pluto.ip.dal.episode.Episodes.Source getSource(String id) {
    return tv.pluto.ip.dal.episode.Episodes.Source.newBuilder()
        .setClip(id)
        .setOutPoint(1)
        .setInPoint(1)
        .build();
  }

  public Clips.GetByCodeAndActiveRegionResponse getByCodeAndActiveRegion(
      String code, String activeRegion) {

    Clips.GetByCodeAndActiveRegionRequest.Builder builder =
        Clips.GetByCodeAndActiveRegionRequest.newBuilder();

    if (code != null) {
      builder.setCode(code);
    }

    if (activeRegion != null) {
      builder.setActiveRegion(activeRegion);
    }

    return blockingStub.getByCodeAndActiveRegion(builder.build());
  }

  public Clips.GetByTagResponse getByTag(String tag, int limit) {
    Clips.GetByTagRequest.Builder builder = Clips.GetByTagRequest.newBuilder().setLimit(limit);

    if (tag != null) builder.setTag(tag);

    return blockingStub.getByTag(builder.build());
  }

  public Clips.GetPromotionalClipsResponse getPromotionalClips() {
    return blockingStub.getPromotionalClips(Clips.GetPromotionalClipsRequest.newBuilder().build());
  }
}
