@file:androidx.media3.common.util.UnstableApi

package cn.learningpad.oraltrainer.sdk

import android.content.Context
import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.DataSource
import androidx.media3.datasource.DefaultDataSource
import androidx.media3.datasource.cache.CacheDataSource
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
import androidx.media3.datasource.cache.SimpleCache
import androidx.media3.datasource.DefaultHttpDataSource
import java.io.File

internal object StreamingCache {
    private var databaseProvider: StandaloneDatabaseProvider? = null
    private var cache: SimpleCache? = null

    @Synchronized
    fun get(context: Context, config: OralTrainerSdkConfig): SimpleCache {
        cache?.let { return it }
        val appContext = context.applicationContext
        val provider = StandaloneDatabaseProvider(appContext)
        val directory = config.cacheDirectory ?: File(appContext.cacheDir, "oral_trainer_media_cache")
        val evictor = LeastRecentlyUsedCacheEvictor(config.maxCacheBytes)
        return SimpleCache(directory, evictor, provider).also {
            databaseProvider = provider
            cache = it
        }
    }

    fun dataSourceFactory(
        context: Context,
        config: OralTrainerSdkConfig,
    ): DataSource.Factory {
        val httpDataSourceFactory = DefaultHttpDataSource.Factory()
            .setUserAgent(config.userAgent)
            .setConnectTimeoutMs(config.connectTimeoutMs)
            .setReadTimeoutMs(config.readTimeoutMs)
            .setAllowCrossProtocolRedirects(true)
        val upstreamFactory = DefaultDataSource.Factory(context.applicationContext, httpDataSourceFactory)

        return CacheDataSource.Factory()
            .setCache(get(context, config))
            .setUpstreamDataSourceFactory(upstreamFactory)
            .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
    }

    @Synchronized
    fun release() {
        cache?.release()
        cache = null
        databaseProvider = null
    }

    @Synchronized
    fun clear(context: Context, config: OralTrainerSdkConfig) {
        val appContext = context.applicationContext
        val directory = config.cacheDirectory ?: File(appContext.cacheDir, "oral_trainer_media_cache")
        val provider = databaseProvider ?: StandaloneDatabaseProvider(appContext)
        cache?.release()
        cache = null
        SimpleCache.delete(directory, provider)
        databaseProvider = null
    }
}

class OralTrainerCache internal constructor(
    private val context: Context,
    private val config: OralTrainerSdkConfig,
) {
    fun sizeBytes(): Long = StreamingCache.get(context, config).cacheSpace

    fun clear() {
        StreamingCache.clear(context, config)
    }
}
