package com.gh.download.cache

import android.net.Uri
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.common.utils.DeviceUtils
import com.gh.gamecenter.common.utils.NetworkUtils
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
import com.google.android.exoplayer2.upstream.cache.CacheDataSource
import com.google.android.exoplayer2.upstream.cache.CacheWriter
import com.halo.assistant.HaloApp
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import tv.danmaku.ijk.media.exo2.ExoSourceManager
import java.util.concurrent.ConcurrentHashMap

object ExoCacheManager {

    private val writers = ConcurrentHashMap<String, CacheWriter>()

    private fun getPreLength(): Long {
        val totalRamSizeOfDevice = DeviceUtils.getTotalRamSizeOfDevice(HaloApp.getInstance().application)
        return if (totalRamSizeOfDevice <= 2 * 1024) {
            if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
                10 * 1024 * 1024L
            } else {
                when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
                    "5G", "4G" -> 10 * 1024 * 1024L
                    "3G" -> 5 * 1024 * 1024L
                    else -> 0L
                }
            }
        } else {
            if (NetworkUtils.isWifiConnected(HaloApp.getInstance().application)) {
                50 * 1024 * 1024L
            } else {
                when (NetworkUtils.getMobileNetworkType(HaloApp.getInstance().application)) {
                    "5G", "4G" -> 20 * 1024 * 1024L
                    "3G" -> 5 * 1024 * 1024L
                    else -> 0L
                }
            }
        }
    }

    fun preload(videoUri: String) {
        val preLength = getPreLength()
        if (preLength == 0L) return
        runOnIoThread(isHeavyWightTask = true) {
            val contentLength = getContentLength(videoUri)
            val cacheLength = if (contentLength >= preLength) preLength else contentLength
            val simpleCache = ExoSourceManager.getCacheSingleInstance(HaloApp.getInstance().application, null)
            val specBuilder = DataSpec.Builder()
                .setUri(Uri.parse(videoUri))
                .setLength(cacheLength)
                .build()
            val dataSource: DataSource = DefaultDataSourceFactory(HaloApp.getInstance()).createDataSource()
            val cacheDataSource = CacheDataSource(simpleCache, dataSource)
            val cacheWriter = CacheWriter(
                cacheDataSource,
                specBuilder,
                true,
                null
            ) { _, _, _ ->
//                debugOnly {
//                    Utils.log("$requestLength-$bytesCached-$newBytesCached")
//                }
            }
            writers[videoUri] = cacheWriter
            try {
                cacheWriter.cache()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    fun cancel(videoUri: String) {
        writers[videoUri]?.cancel()
        writers.remove(videoUri)
    }

    fun cancelAll() {
        val iterator = writers.entries.iterator()
        while (iterator.hasNext()) {
            val entry = iterator.next()
            entry.value.cancel()
            iterator.remove()
        }
    }

    fun getContentLength(downloadUrl: String): Long {
        var contentLength = -1L
        val request = Request.Builder()
            .url(downloadUrl)
            .build()
        var response: Response? = null
        try {
            response = OkHttpClient.Builder().build().newCall(request).execute()
            if (response!!.isSuccessful && response.body() != null) {
                val length = response.body()!!.contentLength()
                contentLength = if (length == 0L) -1L else length
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            response?.close()
        }
        return contentLength
    }
}