package com.twitter.home_mixer.functional_component.gate

import com.twitter.common_internal.analytics.twitter_client_user_agent_parser.UserAgent
import com.twitter.product_mixer.core.feature.Feature
import com.twitter.product_mixer.core.functional_component.gate.Gate
import com.twitter.product_mixer.core.model.common.identifier.GateIdentifier
import com.twitter.product_mixer.core.pipeline.PipelineQuery
import com.twitter.stitch.Stitch
import com.twitter.timelinemixer.clients.persistence.TimelineResponseV3
import com.twitter.timelinemixer.injection.store.persistence.TimelinePersistenceUtils
import com.twitter.timelines.configapi.Param
import com.twitter.timelines.util.client_info.ClientPlatform
import com.twitter.timelineservice.model.rich.EntityIdType
import com.twitter.util.Duration
import com.twitter.util.Time

/**
 * Gate used to reduce the frequency of injections. Note that the actual interval between injections may be
 * less than the specified minInjectionIntervalParam if data is unavailable or missing. For example, being deleted by
 * the persistence store via a TTL or similar mechanism.
 *
 * @param minInjectionIntervalParam the desired minimum interval between injections
 * @param persistenceEntriesFeature the feature for retrieving persisted timeline responses
 */
case class TimelinesPersistenceStoreLastInjectionGate(
  minInjectionIntervalParam: Param[Duration],
  persistenceEntriesFeature: Feature[PipelineQuery, Seq[TimelineResponseV3]],
  entityIdType: EntityIdType.Value)
    extends Gate[PipelineQuery]
    with TimelinePersistenceUtils {

  override val identifier: GateIdentifier = GateIdentifier("TimelinesPersistenceStoreLastInjection")

  override def shouldContinue(query: PipelineQuery): Stitch[Boolean] =
    Stitch(
      query.queryTime.since(getLastInjectionTime(query)) > query.params(minInjectionIntervalParam))

  private def getLastInjectionTime(query: PipelineQuery) = query.features
    .flatMap { featureMap =>
      val timelineResponses = featureMap.getOrElse(persistenceEntriesFeature, Seq.empty)
      val clientPlatform = ClientPlatform.fromQueryOptions(
        clientAppId = query.clientContext.appId,
        userAgent = query.clientContext.userAgent.flatMap(UserAgent.fromString)
      )
      val sortedResponses = responseByClient(clientPlatform, timelineResponses)
      val latestResponseWithEntityIdTypeEntry =
        sortedResponses.find(_.entries.exists(_.entityIdType == entityIdType))

      latestResponseWithEntityIdTypeEntry.map(_.servedTime)
    }.getOrElse(Time.Bottom)
}
