package com.base.browserwhite.ui.activity.webbrowser

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Dialog
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.net.http.SslError
import android.text.Html
import android.util.Log
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import android.webkit.CookieManager
import android.webkit.JavascriptInterface
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.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.applovin.sdk.AppLovinSdkUtils.runOnUiThread
import com.base.browserwhite.MyApplication
import com.base.browserwhite.ads.AdmobMaxHelper
import com.base.browserwhite.ads.AdmobMaxHelper.intervalAdTime
import com.base.browserwhite.ads.AdmobMaxHelper.lastShowInter
import com.base.browserwhite.bean.BookmarkBean
import com.base.browserwhite.bean.ConstObject.downloadDisclaimer
import com.base.browserwhite.bean.ConstObject.webPrivacy
import com.base.browserwhite.bean.DownloadBean
import com.base.browserwhite.bean.HistoryBean
import com.base.browserwhite.databinding.FragmentWebViewBinding
import com.base.browserwhite.ui.activity.download.DownloadAdapter
import com.base.browserwhite.ui.activity.download.DownloadDialog.showDownloadFinishDialog
import com.base.browserwhite.ui.activity.download.DownloadDialog.showDownloadVideoDialog
import com.base.browserwhite.ui.activity.news.NewsActivity
import com.base.browserwhite.ui.fragment.BaseFragment
import com.base.browserwhite.ui.views.DialogViews.showDownloadDisclaimer
import com.base.browserwhite.ui.views.PermissionDialog.showPermissionBottomSheet
import com.base.browserwhite.utils.ActivityLauncher
import com.base.browserwhite.utils.ColorUtils
import com.base.browserwhite.utils.DownloadUtils
import com.base.browserwhite.utils.DownloadUtils.getDownloadJson
import com.base.browserwhite.utils.DownloadUtils.getDownloadJsonBean
import com.base.browserwhite.utils.LogEx
import com.base.browserwhite.utils.PermissionUtils.checkStorePermission
import com.base.browserwhite.utils.SpBeanUtils
import com.base.browserwhite.utils.SpBeanUtils.HISTORY_SP_KEY
import com.base.browserwhite.utils.Utils.dpToPx
import com.google.gson.Gson
import com.liulishuo.filedownloader.FileDownloader
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.File
import java.io.IOException
import java.util.regex.Pattern
import kotlin.random.Random


class WebViewFragment() : BaseFragment<FragmentWebViewBinding>() {

    private val TAG = "WebViewFragment"
    var url: String = ""
    var from: String = ""

    var bookmarkBean: BookmarkBean = BookmarkBean()

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

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

    private var downloadAdapter: DownloadAdapter? = null

    override fun setView() {

        initWebSettings()
        bookmarkBean.url = url
        loadWebView(url)
    }

    var downloadDialog: Dialog? = null
    override fun setListener() {
        super.setListener()
        searchResult = mutableListOf()
        binding.tvReload.setOnClickListener {
            reloadWebView()
        }
        binding.webView.setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            if (scrollY == 0) {
                binding.refreshLayout.setEnabled(true)
            } else {
                binding.refreshLayout.setEnabled(false)
            }
        }
        binding.refreshLayout.setOnRefreshListener {
            lifecycleScope.launch {
                binding.refreshLayout.isRefreshing = true
                delay(Random.nextLong(1500, 2500))
                binding.refreshLayout.isRefreshing = false
            }
            reloadWebView()
        }

        binding.flDownload.setOnClickListener {
            callDownloadDialog()
        }
        binding.webView.setFindListener { activeMatchOrdinal, numberOfMatches, isDoneCounting ->
            LogEx.logDebug(
                TAG,
                "activeMatchOrdinal=$activeMatchOrdinal numberOfMatches=$numberOfMatches isDoneCounting=$isDoneCounting"
            )
            if (numberOfMatches > 0) {
                if (isDoneCounting) {
                    binding.webView.loadUrl("javascript:window.android.onSearchResult(document.body.innerText);")
                }
            } else {
                if (activity is WebBrowserActivity) {
                    (activity as WebBrowserActivity?)?.setSearchNum(0, 0)
                }
                searchResult.clear()
                searchPosition = 0
            }
        }
    }

    private fun callDownloadDialog() {
        if (!downloadDisclaimer) {
            requireContext().showDownloadDisclaimer {}
            downloadDisclaimer = true
            return
        }

        if (!requireContext().checkStorePermission()) {
            val launcher: ActivityLauncher = if (from == "news") {
                (requireActivity() as NewsActivity).launcher
            } else {
                (requireActivity() as WebBrowserActivity).launcher
            }

            requireContext().showPermissionBottomSheet(launcher) {}
            return
        }

        initDownloadAdapter()

        downloadAdapter?.let { adapter ->
            downloadDialog = requireContext().showDownloadVideoDialog(
                adapter, downloadList,
                dismissAction = {
                    downloadDialog = null
                },
            )
        }
    }

    private fun initDownloadAdapter() {
        if (downloadAdapter == null) {
            downloadAdapter = DownloadAdapter(requireActivity())
        }
        downloadAdapter?.downloadAction = {
            downloadDialog?.dismiss()
        }

        downloadAdapter?.downloadFinishAction = { id ->
            downloadDialog?.dismiss()
            val recordFile = requireContext().getDownloadJson()
            val bean = DownloadUtils.getDownloadJsonBean(recordFile).find { it.downloadId == id }
            val file = File(bean?.path ?: "")
            LogEx.logDebug(TAG, "downloadFinishAction id=$id ${bean?.downloadId} ${bean?.name} ${bean?.path}} exists=${file.exists()}")
            bean?.let {
                requireContext().showDownloadFinishDialog(it) { callDownloadDialog() }
            }
        }
    }

    private var keyword = ""

    fun findAll(keyword: String) {
        this.keyword = keyword
        searchResult.clear() // 清空搜索结果
        binding.webView.findAllAsync(keyword)
    }

    private var searchPosition = 0

    fun nextSearch() {
        if (searchResult.isNotEmpty()) {
            searchPosition++
            if (searchPosition >= searchResult.size) {
                searchPosition = 0
            }
            scrollToPosition(true)
        }
    }

    private fun scrollToPosition(position: Boolean) {

        binding.webView.findNext(position)
        searchResult.clear() // 清空搜索结果

    }

    fun lastSearch() {
        if (searchResult.isNotEmpty()) {
            searchPosition--
            if (searchPosition < 0) {
                searchPosition = searchResult.size - 1
            }
            scrollToPosition(false)
        }
    }

    private fun highlightSearchResult() {
        binding.webView.loadUrl("javascript:document.body.innerHTML = document.body.innerHTML.replace(/${keyword}/g, '<span style=\"background-color: #FFD700;\">$0</span>')")
    }

    private lateinit var searchResult: MutableList<Int>

    @JavascriptInterface
    fun onSearchResult(text: String?) {
        LogEx.logDebug(TAG, "onSearchResult")
        text?.let {
            val filteredText = Html.fromHtml(it).toString()
            val pattern = Pattern.compile(keyword, Pattern.CASE_INSENSITIVE)
            val matcher = pattern.matcher(filteredText)
            while (matcher.find()) {
                val start = matcher.start()
                val end = matcher.end()
                searchResult.add(start)
            }
            if (activity is WebBrowserActivity) {
                runOnUiThread {
                    (activity as WebBrowserActivity?)?.setSearchNum(
                        searchPosition + 1, searchResult.size
                    )
                }

            }
            highlightSearchResult()
        }
    }

    private fun dropAndBounceButton(button: View) {
        // 初始位置
        button.isVisible = downloadList.isNotEmpty()

        val startTranslationY = button.translationY

        // 掉落位置
        val dropTranslationY = -(MyApplication.context.dpToPx(60f)).toFloat()
        val dropTranslationY1 = -(MyApplication.context.dpToPx(20f)).toFloat()

        // 回弹高度
        val animator = ValueAnimator.ofFloat(
            dropTranslationY,
            startTranslationY,
            dropTranslationY1,
            startTranslationY
        )
        animator.interpolator = AccelerateDecelerateInterpolator()
        animator.duration = 1000
        animator.addUpdateListener { animation ->
            // 更新按钮的位置
            button.translationY = animation.animatedValue as Float
        }
        animator.start()
        // 创建掉落动画

    }

    fun reloadWebView() {
        binding.llError.visibility = View.GONE
        binding.webView.visibility = View.VISIBLE
        binding.progressBar.visibility = View.VISIBLE
        binding.progressBar.progress = 0
        downloadList.clear()
        binding.flDownload.visibility = View.GONE
        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() {

        val webSettings = binding.webView.settings
        webSettings.allowFileAccess = true// 设置允许访问文件数据
        webSettings.setSupportZoom(false)
        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
        webSettings.setUseWideViewPort(false);
        webSettings.setLoadsImagesAutomatically(true); // 确保自动加载图片

        //设置WebChromeClient
        binding.webView.webChromeClient = object : WebChromeClient() {

            override fun onProgressChanged(view: WebView, newProgress: Int) {
                LogEx.logDebug(TAG, "onProgressChanged newProgress=$newProgress")

                binding.progressBar.progress = newProgress
                if (binding.progressBar.progress >= 100) {
                    binding.progressBar.visibility = View.GONE
                }
            }

            override fun onReceivedTitle(view: WebView?, title: String?) {
                super.onReceivedTitle(view, title)
                bookmarkBean.name = title ?: "about:black"
            }

            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
        }
        val packageManager = context?.packageManager

        binding.webView.webViewClient = object : WebViewClient() {


            override fun onLoadResource(view: WebView?, url: String?) {
                super.onLoadResource(view, url)
                if (url?.endsWith(".mp4") == true) {
                    LogEx.logDebug(TAG, "onLoadResource url=$url")
                    addVideoLink(url)
                }
            }

            override fun shouldOverrideUrlLoading(
                view: WebView?,
                request: WebResourceRequest?
            ): Boolean {
                LogEx.logDebug(TAG, "shouldOverrideUrlLoading")
                if (request != null) {
                    val uri = request.url
                    val scheme = uri.scheme
                    // 检查 URL 是否是 scheme 类型
                    if (scheme != null && (scheme == "http" || scheme == "https")) {
                    } else {
                        val intent = Intent(Intent.ACTION_VIEW, uri)
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                        if (packageManager != null && intent.resolveActivity(packageManager) != null) {
                            startActivity(intent)
                        }
                        return true // 返回 true，表示 URL 已经被处理
                    }
                    return super.shouldOverrideUrlLoading(view, request)
                }
                return false
            }

            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                super.onPageStarted(view, url, favicon)
                downloadList.clear()
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                LogEx.logDebug(TAG, "onPageFinished")
                super.onPageFinished(view, url)
                val tittle = view?.title.toString()
                bookmarkBean.name = tittle
                bookmarkBean.url = url ?: ""
                onPageFinished?.invoke(url)
                onPageFinished = null

                if (!webPrivacy) {
                    //添加历史记录
                    SpBeanUtils.addSpBean(
                        HISTORY_SP_KEY,
                        HistoryBean(
                            name = tittle, url = url ?: "",
                            time = System.currentTimeMillis(),
                            color = ColorUtils.getRandomColor()
                        )
                    )
                }
            }

            override fun onReceivedSslError(
                view: WebView?,
                handler: SslErrorHandler?,
                error: SslError?
            ) {
                LogEx.logDebug(TAG, "onReceivedSslError")
                super.onReceivedSslError(view, handler, error)
                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)
            }
        }

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


    }

    private val downloadList = arrayListOf<DownloadBean>()


    @SuppressLint("NotifyDataSetChanged")
    fun addVideoLink(addUri: String) {
        if (downloadList.map { it.url }.contains(addUri)) return

        val olderList = arrayListOf<DownloadBean>()
        val recordFile = requireContext().getDownloadJson()
        olderList.addAll(getDownloadJsonBean(recordFile, Gson()))
        olderList.forEach {
            it.status = FileDownloader.getImpl().getStatus(it.downloadId, it.path)
        }

        val olderBean = olderList.findLast { it.url == addUri }
        if (olderBean != null) {
            LogEx.logDebug(TAG, "old path=${olderBean.path} ${olderBean.downloadId}")
            downloadList.add(olderBean.apply { uiType = 2 })
        } else {
            downloadList.add(DownloadBean(url = addUri).apply {
                name = addUri.split("/").last()
                uiType = 2
            })
        }

        binding.tvDownloadNumber.text = downloadList.size.toString()
        dropAndBounceButton(binding.flDownload)
        downloadList.forEach {
            LogEx.logDebug(TAG, "${it.url} ${it.size} ${it.downloadId} ${it.path}")
        }

        lifecycleScope.launch(Dispatchers.IO) {
            downloadList.filter { it.size <= 0 }.forEach {
                fastGetSize(it)
            }
            launch(Dispatchers.Main) {
                downloadAdapter?.submitList(downloadList)
                downloadAdapter?.notifyDataSetChanged()
            }
        }
    }


    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()
    }


    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"
        }
    }

    private fun fastGetSize(bean: DownloadBean) = runCatching {
        if (bean.size == -1L) {
            val client = OkHttpClient()

            LogEx.logDebug(TAG, "fastGetSize ${bean.url}")
            val request = Request.Builder()
                .url(bean.url)
                .head() // 发送 HEAD 请求
                .build()

            try {
                client.newCall(request).enqueue(object : Callback {
                    override fun onFailure(call: Call, e: IOException) {
                        // 处理请求失败的情况
                        LogEx.logDebug(TAG, "onFailure")
                    }

                    override fun onResponse(call: Call, response: Response) {
                        if (response.isSuccessful) {
                            val contentLength = response.header("Content-Length") // 获取内容长度
                            contentLength?.let {
                                // 将内容长度转换为 Long 类型
                                val videoSize = it.toLong()
                                // 在这里使用视频大小，例如在主线程更新 UI 或存储到变量中
                                bean.size = videoSize
                                LogEx.logDebug(TAG, "videoSize=$videoSize")
                            }
                        }
                    }
                })
            } catch (e: Exception) {
                // 处理异常情况
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        binding.webView.destroy()
    }

    override fun onResume() {
        super.onResume()
        if (requireContext().checkStorePermission()) {
            upDateDownloadList()
        }
    }

    private fun upDateDownloadList() {
        downloadList.forEach {
            it.status = FileDownloader.getImpl().getStatus(it.url, it.path)
        }
        downloadAdapter?.submitList(downloadList)
    }

}