package com.suno.android.gating import androidx.annotation.VisibleForTesting import com.suno.android.gating.StatsigAccessor.ExperimentParam import com.suno.android.gating.StatsigAccessor.Gate import com.suno.android.gating.statsig.Experiment import com.suno.android.gating.statsig.FeatureGate import com.suno.android.gating.statsig.FeatureValue import com.suno.android.gating.statsig.ParameterStoreAccessor import com.suno.android.gating.statsig.StatsigFeatureDataSource import javax.inject.Inject interface FeatureManager { fun hasFeature( feature: Feature, ): Boolean fun getFeatureValue( feature: Feature, ): T } class DefaultFeatureManager @Inject constructor( private val statsigManager: StatsigFeatureDataSource, ) : FeatureManager { override fun hasFeature( feature: Feature, ): Boolean { val statsigAccessor = feature.toStatsigAccessor() return getStatsigValue(statsigAccessor).value } override fun getFeatureValue( feature: Feature, ): T { val statsigAccessor = feature.toStatsigAccessor() return getStatsigValue(statsigAccessor) } private fun getStatsigValue( accessor: StatsigAccessor, ): T = when (accessor) { is Gate -> FeatureValue.Boolean(statsigManager.checkGate(accessor.featureGate)) as T is ExperimentParam -> statsigManager.fetchExperimentParam(accessor.experiment) is StatsigAccessor.ParameterStoreValue -> statsigManager.fetchParamStoreValue( parameterStoreAccessor = accessor.paramStoreAccessor, ) } } @VisibleForTesting sealed interface StatsigAccessor { @JvmInline value class Gate( val featureGate: FeatureGate, ) : StatsigAccessor @JvmInline value class ExperimentParam( val experiment: Experiment, ) : StatsigAccessor @JvmInline value class ParameterStoreValue( val paramStoreAccessor: ParameterStoreAccessor, ) : StatsigAccessor } @VisibleForTesting fun Feature.toStatsigAccessor(): StatsigAccessor = when (this) { Feature.AuthFacebook -> Gate(FeatureGate.AUTH_FACEBOOK) Feature.Downloads -> Gate(FeatureGate.DOWNLOADS) Feature.VideoCoverPlayer -> Gate(FeatureGate.VIDEO_COVER_PLAYER) Feature.VideoCoverPreview -> Gate(FeatureGate.VIDEO_COVER_PREVIEW) Feature.CommentsMentions -> Gate(FeatureGate.COMMENTS_MENTIONS) Feature.CaptionMentions -> Gate(FeatureGate.CAPTION_MENTIONS) Feature.ShowRepeatButton -> Gate(FeatureGate.SHOW_REPEAT_BUTTON) Feature.ShowShuffleButton -> Gate(FeatureGate.SHOW_SHUFFLE_BUTTON) Feature.ShowCustomAdvancedOptions -> Gate(FeatureGate.SHOW_CUSTOM_ADVANCED_OPTIONS) Feature.ShowShareVideo -> Gate(FeatureGate.SHOW_SHARE_VIDEO) Feature.EditSongArt -> Gate(FeatureGate.EDIT_SONG_ART) Feature.ClipDisableDownloads -> Gate(FeatureGate.CLIP_DISABLE_DOWNLOADS) Feature.CreateAudioRecord -> Gate(FeatureGate.CREATE_AUDIO_RECORD) Feature.CreateAudioUpload -> Gate(FeatureGate.CREATE_AUDIO_UPLOAD) Feature.CreateAudioLibrary -> Gate(FeatureGate.CREATE_AUDIO_LIBRARY) Feature.CreateCustomEnhanceStyle -> Gate(FeatureGate.CREATE_CUSTOM_ENHANCE_STYLE) Feature.ShowAudioInfluenceSlider -> Gate(FeatureGate.SHOW_AUDIO_INFLUENCE_SLIDER) Feature.UseCreateBottomSheet -> Gate(FeatureGate.USE_CREATE_BOTTOM_SHEET) Feature.ShowCreateCustomModeResetFields -> Gate( FeatureGate.SHOW_CREATE_CUSTOM_MODE_RESET_FIELDS, ) Feature.ShowV45PlusDialog -> Gate(FeatureGate.SHOW_V45PLUS_DIALOG) Feature.CreateAudioTaskCover -> Gate(FeatureGate.CREATE_AUDIO_TASK_COVER) Feature.CreateAudioTaskExtend -> Gate(FeatureGate.CREATE_AUDIO_TASK_EXTEND) Feature.RemixClip -> Gate(FeatureGate.REMIX_CLIP) Feature.AddProfilePicture -> Gate(FeatureGate.ADD_PROFILE_PICTURE) Feature.ShowCast -> Gate(FeatureGate.SHOW_CAST) Feature.CreateProjectSelection -> Gate(FeatureGate.CREATE_PROJECT_SELECTION) Feature.ShowAudioCreateOnSimple -> ExperimentParam(Experiment.AudioCreateInSimple) Feature.NewLogging -> Gate(FeatureGate.NEW_LOGGING) Feature.HooksCreate -> Gate(FeatureGate.HOOKS_CREATE) Feature.HooksInAppNotifications -> Gate(FeatureGate.HOOKS_INAPP_NOTIFICATIONS) Feature.ShowV5PromoDialog -> Gate(FeatureGate.SHOW_V5_PROMO_DIALOG) Feature.Workspaces -> ExperimentParam(Experiment.Workspaces) Feature.HooksCreateCamera -> Gate(FeatureGate.HOOKS_CREATE_CAMERA) Feature.HooksCreateUpload -> TODO() Feature.HooksDownload -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.AllowHookDownload) Feature.HooksDownloadSelf -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.AllowHookSelfDownload) Feature.ShowPromoDialog -> Gate(FeatureGate.PROMO_DIALOG) Feature.OrpheusChat -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.OrpheusChatEnabled) Feature.OrpheusProjects -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.OrpheusProjectsEnabled) Feature.HooksFeedLocation -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.HooksFeedLocation) Feature.HooksFeedType -> StatsigAccessor.ParameterStoreValue(ParameterStoreAccessor.HooksFeedType) Feature.BillingV2 -> Gate(FeatureGate.BILLING_V2) Feature.RealtimeSongGeneration -> StatsigAccessor.ParameterStoreValue( ParameterStoreAccessor.SongGenerationRealtimeEnabled, ) Feature.SongGenerationPollingIntervalSeconds -> StatsigAccessor.ParameterStoreValue( ParameterStoreAccessor.SongGenerationPollingIntervalSeconds, ) Feature.BlackFridayBanner -> Gate(FeatureGate.BLACK_FRIDAY_BANNER) } as StatsigAccessor