package com.base.browserwhite.ui.fragment

import android.annotation.SuppressLint
import android.net.Uri
import android.net.http.SslError
import android.os.Build
import android.view.View
import android.webkit.CookieManager
import android.webkit.JsResult
import android.webkit.SslErrorHandler
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebSettings
import android.webkit.WebStorage
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.lifecycle.lifecycleScope
import com.base.browserwhite.databinding.FragmentWebViewBinding
import com.base.browserwhite.utils.LogEx
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlin.random.Random


class WebViewFragment(val url: String) : BaseFragment<FragmentWebViewBinding>() {

    private val TAG = "WebViewFragment"
    private var job: Job? = null

    override val binding: FragmentWebViewBinding by lazy {
        FragmentWebViewBinding.inflate(layoutInflater)
    }

    var onPageFinished: ((uri: String?) -> Unit)? = null


    override fun setView() {
        initWebSettings()
        loadWebView(url)
    }

    override fun setListener() {
        super.setListener()
        binding.tvReload.setOnClickListener {
            reloadWebView()
        }
        binding.refreshLayout.setOnRefreshListener {
            lifecycleScope.launch {
                binding.refreshLayout.isRefreshing = true
                delay(Random.nextLong(1500, 2500))
                binding.refreshLayout.isRefreshing = false
            }
            reloadWebView()
        }
    }

    private fun reloadWebView() {
        binding.llError.visibility = View.GONE
        binding.webView.visibility = View.VISIBLE
        binding.progressBar.visibility = View.VISIBLE
        binding.progressBar.progress = 0
        binding.webView.reload()
    }

    fun loadWebView(loadUrl: String) {
        binding.llError.visibility = View.GONE
        binding.webView.visibility = View.VISIBLE
        LogEx.logDebug(TAG, "loadUrl=$loadUrl")
        binding.webView.loadUrl(loadUrl)
    }

    @SuppressLint("SetJavaScriptEnabled")
    fun initWebSettings() {
//        binding.webView.isFocusableInTouchMode = true
//        binding.webView.isFocusable = true

        val webSettings = binding.webView.settings
        webSettings.allowFileAccess = true// 设置允许访问文件数据
        webSettings.setSupportZoom(true)
        webSettings.builtInZoomControls = true
        webSettings.cacheMode = WebSettings.LOAD_NO_CACHE
        webSettings.domStorageEnabled = true
        webSettings.databaseEnabled = true
        @Suppress("DEPRECATION")
        webSettings.allowFileAccessFromFileURLs = true
        WebStorage.getInstance().deleteAllData()

        // 关键性代码，这里要给webView添加这行代码，才可以点击之后正常播放音频。记录一下。
        webSettings.mediaPlaybackRequiresUserGesture = false

        //设置WebView属性，能够执行Javascript脚本
        webSettings.javaScriptEnabled = true

        //设置混合内容模式：对于HTTPS和HTTP混合内容的加载，需要设置WebView以允许混合内容：
        webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW

        //使用CookieManager设置允许跨域Cookie
        CookieManager.getInstance().setAcceptThirdPartyCookies(binding.webView, true)

        //适应屏幕设置
        webSettings.useWideViewPort = true
        webSettings.loadWithOverviewMode = true

        //网页使用localStorage等Web存储API，需要启用DOM存储
        webSettings.domStorageEnabled = true


        //设置WebChromeClient
        binding.webView.webChromeClient = object : WebChromeClient() {
            override fun onProgressChanged(view: WebView, newProgress: Int) {
                LogEx.logDebug(TAG, "onProgressChanged newProgress=$newProgress")
                binding.progressBar.progress = newProgress + 15
                if (binding.progressBar.progress >= 100) {
                    binding.progressBar.visibility = View.GONE
                }
            }

            override fun onReceivedTitle(view: WebView?, title: String?) {
                super.onReceivedTitle(view, title)
            }

            override fun onShowFileChooser(
                webView: WebView?,
                filePathCallback: ValueCallback<Array<Uri?>?>,
                fileChooserParams: FileChooserParams?
            ): Boolean {
                return true
            }

            override fun onJsAlert(
                view: WebView?,
                url: String?,
                message: String?,
                result: JsResult?
            ): Boolean = true
        }
        binding.webView.webViewClient = object : WebViewClient() {
            override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                LogEx.logDebug(TAG, "shouldOverrideUrlLoading")
                val url = request?.url.toString()
                binding.llError.visibility = View.GONE
                view?.loadUrl(url)
                return true
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                LogEx.logDebug(TAG, "onPageFinished")
                super.onPageFinished(view, url)
                onPageFinished?.invoke(url)
                job?.cancel()
            }

            override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
                LogEx.logDebug(TAG, "onReceivedSslError")
                super.onReceivedSslError(view, handler, error)
                job?.cancel()
                binding.webView.visibility = View.GONE
                binding.llError.visibility = View.GONE
                if (error != null) {
                    val domain = error.url
                    // 获取错误码
                    val primaryError = error.primaryError
                    // 根据错误码获取错误描述的中英文对照文本
                    val errorString = getSslErrorString(primaryError)
                    binding.tvErrorReason.text = errorString
                }
            }

            override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
                LogEx.logDebug(TAG, "onReceivedError ${error?.errorCode} ${error?.description}")
                super.onReceivedError(view, request, error)
                return
//                if (error?.errorCode == -1) {
//                    //-1 net::ERR_BLOCKED_BY_ORB 跨域读取不影响显示
//                    return
//                }
//                if (error?.errorCode == -6) {
//                    //-6 net::ERR_BLOCKED_BY_ORB 服务器拒绝连接，是服务的锅
//                    return
//                }
//                job?.cancel()
//                binding.webView.visibility = View.GONE
//                binding.llError.visibility = View.VISIBLE
//                if (error != null) {
//                    // 获取错误码
//                    val errorCode = error.errorCode
//                    // 获取错误描述
//                    val description = error.description
//
//                    // 创建错误信息文本
//                    val errorText = "Error ${errorCode}: $description"
//
//                    // 打印错误信息，或者根据需要进行其他处理
//                    binding.tvErrorReason.text = errorText
//                }
            }
        }

        //设置Cookie
        val instance = CookieManager.getInstance()
        instance.setAcceptThirdPartyCookies(binding.webView, true)

    }


    fun canGoBack(): Boolean {
        return binding.webView.canGoBack()
    }

    fun canGoForward(): Boolean {
        return binding.webView.canGoForward()
    }

    fun goBack() {
        return binding.webView.goBack()
    }

    fun goForward() {
        return binding.webView.goForward()
    }


    fun javascriptBack() {
        binding.webView.evaluateJavascript("window.history.back();", null)
    }


    private fun getSslErrorString(error: Int): String {
        return when (error) {
            SslError.SSL_DATE_INVALID -> "Date Invalid: The certificate's date is incorrect or the certificate has expired."
            SslError.SSL_EXPIRED -> "Expired: The SSL certificate has expired."
            SslError.SSL_IDMISMATCH -> "Hostname Mismatch: The hostname in the certificate does not match the requested hostname."
            SslError.SSL_INVALID -> "Invalid: The certificate is invalid."
            SslError.SSL_NOTYETVALID -> "Not Yet Valid: The certificate is not yet valid."
            SslError.SSL_UNTRUSTED -> "Untrusted: The certificate authority is not trusted."
            else -> "Unknown Error"
        }
    }

}