package com.adealink.weparty.webview

import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Outline
import android.net.http.SslError
import android.os.Build
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.ViewOutlineProvider
import android.webkit.CookieManager
import android.webkit.SslErrorHandler
import androidx.core.net.toUri
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.LifecycleOwner
import com.adealink.frame.data.json.toJsonErrorNull
import com.adealink.frame.ext.isViewBindingValid
import com.adealink.frame.locale.language.languageManager
import com.adealink.frame.log.Log
import com.adealink.frame.mvvm.view.viewBinding
import com.adealink.frame.network.http.interceptor.KEY_API
import com.adealink.frame.network.http.interceptor.KEY_CHANNEL
import com.adealink.frame.network.http.interceptor.KEY_DEVICE
import com.adealink.frame.network.http.interceptor.KEY_NETWORK
import com.adealink.frame.network.http.interceptor.KEY_PACKAGE_NAME
import com.adealink.frame.network.http.interceptor.KEY_PLATFORM
import com.adealink.frame.network.http.interceptor.KEY_TIME
import com.adealink.frame.network.http.interceptor.KEY_TOKEN
import com.adealink.frame.network.http.interceptor.KEY_UDID
import com.adealink.frame.network.http.interceptor.KEY_VERSION_CODE
import com.adealink.frame.router.Router
import com.adealink.frame.router.annotation.BindExtra
import com.adealink.frame.util.AppUtil
import com.adealink.frame.util.PackageUtil
import com.adealink.frame.util.getDeviceName
import com.adealink.frame.util.naviBarHeightDp
import com.adealink.frame.util.statusBarHeightDp
import com.adealink.weparty.App
import com.adealink.weparty.BuildConfig
import com.adealink.weparty.R
import com.adealink.weparty.commonui.BaseFragment
import com.adealink.weparty.commonui.ext.dp
import com.adealink.weparty.databinding.FragmentWebviewBinding
import com.adealink.weparty.module.webview.Web
import com.adealink.weparty.module.webview.Web.Common.Companion.EXTRA_TOP_RADIUS
import com.adealink.weparty.storage.AppPref
import com.adealink.weparty.webview.callback.IWebViewCallback
import com.adealink.weparty.webview.callback.IWebViewFragmentCallback
import com.adealink.weparty.webview.component.ErrorComp
import com.adealink.weparty.webview.constant.NATIVE_JS_BRIDGE
import com.adealink.weparty.webview.constant.NavigationBarMode
import com.adealink.weparty.webview.constant.TAG_WEB_FRAGMENT
import com.adealink.weparty.webview.datasource.local.WebLocalService
import com.adealink.weparty.webview.jsbridge.JSBridge
import com.adealink.weparty.webview.jsbridge.data.NativeMessage
import com.adealink.weparty.webview.jsnativemethod.addCommonMethod
import com.adealink.weparty.webview.payermax.SpWebChromeClient
import com.adealink.weparty.webview.payermax.SpWebViewClient
import com.adjust.sdk.webbridge.AdjustBridge
import com.ushareit.easysdk.web.util.SPWebHelper


class WebViewFragment : BaseFragment(R.layout.fragment_webview),
    IWebViewCallback {

    @BindExtra(Web.Common.EXTRA_LOADING_URL, desc = "加载图标链接")
    var loadingUrl: String? = null

    @BindExtra(Web.Common.EXTRA_DIALOG_TAG, desc = "dialog的tag")
    var fgTag: String? = ""

    private val binding by viewBinding(FragmentWebviewBinding::bind)
    private var url: String = ""

    private var topRadius: Int = 0

    private var errorComp: ErrorComp? = null

    private var transparentBgWhenPageFinish = false
    private var transparentBg = false

    private var webFragmentCallback: IWebViewFragmentCallback? = null

    private val webHelper by lazy { SPWebHelper() }
    private var isPayerMaxPage = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Router.bind(this)
    }

    override fun initViews() {
        super.initViews()
        val topRadius = arguments?.getInt(EXTRA_TOP_RADIUS) ?: 16.dp()
        binding.webView.outlineProvider = object : ViewOutlineProvider() {
            override fun getOutline(view: View, outline: Outline) {
                val left = 0
                val top = 0
                val right = view.width
                val bottom = view.height

                //top corners
                outline.setRoundRect(
                    left,
                    top,
                    right,
                    bottom + topRadius,
                    topRadius.toFloat()
                )
            }
        }
        binding.webView.clipToOutline = true
        binding.webView.webViewCallback = this

        if (transparentBg) {
            binding.root.background = null
            binding.webView.setBackgroundColor(0)
            binding.webView.background?.alpha = 0
        }

        initJsBridge()
        initPayerMaxPageIfNeed()
        initAdjust()
    }

    private fun initJsBridge() {
        binding.webView.getJSBridge(NATIVE_JS_BRIDGE)?.let { bridge ->
            bridge.addCommonMethod(binding.webView)
        }
    }

    private fun initPayerMaxPageIfNeed() {
        val act = activity ?: return
        var host: String? = null
        if (url.isEmpty().not()) {
            host = url.toUri().host
        }
        if (host?.contains("payermax") == true) {
            isPayerMaxPage = true
        }
        val commonWebChromeClient = binding.webView.getCommonWebChromeClient()
        val commonWebViewClient = binding.webView.getCommonWebViewClient()
        val spWebChromeClient = SpWebChromeClient(webHelper, commonWebChromeClient)
        val spWebViewClient = SpWebViewClient(act, binding.webView, commonWebViewClient)
        webHelper.initWebView(
            AppUtil.application,
            act,
            binding.webView,
            spWebChromeClient,
            spWebViewClient
        )
    }

    private fun initAdjust() {
        AdjustBridge.registerAndGetInstance(AppUtil.application, binding.webView)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (isPayerMaxPage) {
            webHelper.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        webHelper.onActivityResult(requestCode, resultCode, data)
    }

    override fun initComponents() {
        super.initComponents()
        errorComp =
            ErrorComp(
                this,
                binding.webView,
                binding.errorView,
                reload = { loadUrl(url) }
            ).apply { attach() }
    }

    override fun onResume() {
        super.onResume()
        notifyResumeMessage()
    }

    private fun notifyResumeMessage() {
//        notifyNativeMessage(NativeMessage<Any>(NativeMessageType.MSG_ON_RESUME.msgType))
    }

    fun showUrl(url: String) {
        this.url = url
        if (isAdded) {
            loadUrl(url)
        }
    }

    fun replaceAndShow(fragmentManager: FragmentManager, contentId: Int, url: String) {
        Log.d(TAG_WEB_FRAGMENT, "replaceAndShow, url:$url")
        this.url = url
        if (isAdded) {
            loadUrl(url)
            return
        }
        fragmentManager.beginTransaction()
            .replace(contentId, this, "WebFragment")
            .commit()
        showUrl(url)
    }

    fun getWebView(): BaseWebView? {
        if (!isAdded) {
            return null
        }
        return binding.webView
    }

    fun setTopRadius(topRadius: Int) {
        this.topRadius = topRadius
    }

    fun setTransparentBgWhenPageFinish() {
        this.transparentBgWhenPageFinish = true
    }

    fun setTransparentBg() {
        this.transparentBg = true
    }

    fun setWebFragmentCallback(callback: IWebViewFragmentCallback?) {
        this.webFragmentCallback = callback
    }

    override fun loadData() {
        super.loadData()
        loadUrl(url)
    }

    private fun loadUrl(url: String) {
        errorComp?.hideError()
        binding.webView.loadUrl(url)
    }

    override val lifeCycleOwner: LifecycleOwner
        get() = viewLifecycleOwner

    override fun closeWebView() {
        webFragmentCallback?.closeWebView()
    }

    override fun setTitle(title: String?) {
        webFragmentCallback?.setTitle(title)
    }

    override fun beforeLoadUrl(url: String) {
        val cookieManager: CookieManager = CookieManager.getInstance()
        cookieManager.setAcceptCookie(true)
        // 设置多个 Cookie
        val cookies = mutableMapOf<String, String>()
        cookies.put(
            "GAMI-web_auth_token",
            AppPref.token
        )
        cookies.put(
            "GAMI-web_app_locale",
            languageManager?.getLanguageCode() ?: ""
        )

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
            && (activity?.isInMultiWindowMode == true || activity?.isInPictureInPictureMode == true)) {
            //画中画/多窗口
            cookies.put(
                "GAMI-cookie_safe_area",
                "0|0"
            )
        } else {
            cookies.put(
                "GAMI-cookie_safe_area",
                "${(activity?.statusBarHeightDp() ?: 0)}|${(activity?.naviBarHeightDp() ?: 0)}"
            )
        }
        for (entry in cookies) {
            val cookieString: String = entry.key + "=" + entry.value + "; path=/"
            cookieManager.setCookie(url, cookieString)
        }
        // 同步 Cookie
        cookieManager.flush()
    }

    /**
     * 详见: https://mimolive.sg.larksuite.com/wiki/ZYliwjteIilW5XkmdhtlysIWgGg
     */
    override fun onPageStarted(url: String?, favicon: Bitmap?) {
        binding.progressIndicator.visibility = View.VISIBLE
        loadJSUrl("javascript:window.localStorage.setItem('GAMI-web_auth_token', '${AppPref.token}')")
        loadJSUrl("javascript:window.localStorage.setItem('GAMI-web_app_locale', '${languageManager?.getLanguageCode() ?: ""}')")
        loadJSUrl(
            "javascript:window.GAMI_BRIDGE={" +
                    "\"requestHeader\":${requestHeader()}," +
                    "\"safeArea\":\"${(activity?.statusBarHeightDp() ?: 0)}|${(activity?.naviBarHeightDp() ?: 0)}\"" +
                    "}"
        )
    }

    fun requestHeader(): String {
        val currentTs = System.currentTimeMillis()
        val deviceName = getDeviceName()
        val headers = mutableMapOf<String, String>()
        headers[KEY_TOKEN] = AppPref.token
        headers[KEY_UDID] = App.instance.deviceIdService.getMemOldDeviceId()
        headers[KEY_PACKAGE_NAME] = PackageUtil.getPackageName()
        headers[KEY_DEVICE] = deviceName
        headers[KEY_PLATFORM] = "1"
        headers[KEY_CHANNEL] = "official"
        headers[KEY_API] = "1"
        headers[KEY_VERSION_CODE] = BuildConfig.VERSION_CODE.toString()
        headers[KEY_NETWORK] = "5g"
        headers[KEY_TIME] = currentTs.toString()
        return (toJsonErrorNull(headers) ?: "").also {
            Log.d(TAG_WEB_FRAGMENT, "requestHeader, header:$it")
        }
    }

    override fun onPageFinished(url: String?) {
        binding.progressIndicator.visibility = View.GONE
        WebLocalService.initWebVersion()
        if (transparentBgWhenPageFinish) {
            binding.root.background = null
            binding.webView.setBackgroundColor(0)
            binding.webView.background?.alpha = 0
        }
    }

    override fun onProgressChanged(progress: Int) {
        binding.progressIndicator.setProgressCompat(progress, true)
    }

    override fun onReceivedError(url: String?, errorCode: Int, description: String?) {
        errorComp?.showError("$errorCode:$description")
    }

    override fun onReceivedSslError(handler: SslErrorHandler?, error: SslError?) {
        errorComp?.showError()
    }

    override fun isHostActive(): Boolean {
        val hostActivity = activity ?: return false
        return !hostActivity.isDestroyed && isAdded
    }

    override fun setImmersionMode() {
        webFragmentCallback?.setImmersionMode()
    }

    override fun setNavigationBarMode(mode: NavigationBarMode) {
        webFragmentCallback?.setNavigationBarMode(mode)
    }

    override fun hideNavigationBar() {
        webFragmentCallback?.hideNavigationBar()
    }

    override fun <T> notifyNativeMessage(message: NativeMessage<T>) {
        if (!isViewBindingValid()) {
            return
        }
        binding.webView.notifyNativeMessage(message)
    }

    override fun getJsBridge(name: String): JSBridge? {
        if (!isViewBindingValid()) {
            return null
        }
        return binding.webView.getJSBridge(name)
    }

    override fun url(): String? {
        return url
    }

    override fun onPageLoadSuccess() {
        //loadJSUrl("javascript:window.localStorage.setItem('GAMI-web_auth_token', 'xxxx')")
    }

    private fun loadJSUrl(url: String) {
        loadUrl(url)
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (!isViewBindingValid()) {
            return false
        }
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (onBackPressed()) {
                return true
            }
        }
        return false
    }

    override fun onBackPressed(): Boolean {
        if (binding.webView.canGoBack()) {
            binding.webView.goBack()
            return true
        }

        return false
    }

    override fun onDestroyView() {
        AdjustBridge.unregister()
        super.onDestroyView()
        binding.webView.onDestroy()
    }
}