package com.gh.gamecenter.qa.article.detail

import android.annotation.SuppressLint
import android.content.Context
import android.content.MutableContextWrapper
import android.view.ViewGroup
import android.webkit.WebResourceResponse
import android.webkit.WebView
import com.gh.common.util.PackageUtils
import com.gh.common.view.RichEditor
import com.gh.gamecenter.common.utils.EnvHelper
import com.gh.gamecenter.common.utils.removeFromParent
import com.gh.gamecenter.core.utils.MD5Utils
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query
import retrofit2.http.Streaming
import retrofit2.http.Url
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.TimeUnit

/**
 * 社区文章详情-Web资源缓存管理类
 */
@SuppressLint("StaticFieldLeak")
object ArticleDetailWebCacheManager {

    private lateinit var cacheDir: File

    private var isInit = false

    private var preInitialedWebViewMap: HashMap<Context, RichEditor> = hashMapOf()

    @SuppressLint("CheckResult")
    fun init(applicationContext: Context) {
        if (!PackageUtils.checkWebViewIsAvailable(applicationContext)) {
            return
        }

        if (isInit) return

        isInit = true

        RichEditor(MutableContextWrapper(applicationContext))

        this.cacheDir = File(applicationContext.cacheDir, "article/web").apply {
            if (!exists()) mkdirs()
        }

        val cacheUrlList = mutableListOf(
            "https://and-static.ghzs66.com/web/website-static/lib/polyfill.min.js",
            "https://and-static.ghzs66.com/web/dplayer/DPlayer.min.js"
        )

        if (!EnvHelper.isDevEnv) {
            cacheUrlList.add("https://and-static.ghzs66.com/web/js/halo.js")
            cacheUrlList.add("https://and-static.ghzs66.com/web/css/halo.css")
        }

        val okHttpClient = OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .writeTimeout(30, TimeUnit.SECONDS)
            .build()

        val retrofit = Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl("https://and-static.ghzs66.com")
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build()

        val apiService = retrofit.create(ApiService::class.java)

        val requestSingleList = cacheUrlList.map { url ->
            apiService.downloadFile(url, System.currentTimeMillis() / 1000)
                .map {
                    val file = File(cacheDir, MD5Utils.getUrlMD5(url)).apply {
                        if (!exists()) createNewFile()
                    }
                    val inputStream = it.byteStream()
                    val outputStream = FileOutputStream(file)
                    inputStream.copyTo(outputStream, DEFAULT_BUFFER_SIZE)
                    file
                }
        }

        Single.zip(requestSingleList) {}
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({}, {})
    }

    /**
     * 预初始化 WebView
     */
    fun preInitRichEditor(context: Context) {
        if (!PackageUtils.checkWebViewIsAvailable(context)) {
            return
        }

        // 避免未正常初始化的情况
        if (!isInit) {
            init(context.applicationContext)
        }

        preInitialedWebViewMap[context] = RichEditor(context)
    }

    fun attachToRichEditor(parent: ViewGroup): RichEditor {
        val richEditor = (preInitialedWebViewMap[parent.context] ?: RichEditor(parent.context)).apply {
            setWebResourceRequestInterceptor { view, url -> shouldInterceptRequest(view, url) }
        }

        // 避免已使用的 RichEditor 被复用
        if (richEditor.parent != null) {
            richEditor.removeFromParent()
        }

        parent.addView(
            richEditor,
            ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        )
        return richEditor
    }

    fun detachFromRichEditor(context: Context?) {
        preInitialedWebViewMap.remove(context)
    }

    /**
     * 拦截WebView的资源请求，并返回URL对应的缓存数据
     */
    private fun shouldInterceptRequest(view: WebView, url: String): WebResourceResponse? {
        val urlWithoutQueryParams = url.split("?")[0]

        val cacheFile = File(cacheDir, MD5Utils.getUrlMD5(urlWithoutQueryParams))
        if (!cacheFile.exists()) {
            return null
        }

        val mimeType = if (urlWithoutQueryParams.endsWith(".js")) {
            "text/javascript"
        } else if (urlWithoutQueryParams.endsWith(".css")) {
            "text/css"
        } else null

        return WebResourceResponse(mimeType, "utf-8", cacheFile.inputStream())
    }

    interface ApiService {
        @GET
        @Streaming
        fun downloadFile(@Url url: String, @Query("timestamp") timestamp: Long): Single<ResponseBody>
    }
}