package com.tencent.qian.webview.client

import android.content.Context
import android.graphics.Bitmap
import android.net.http.SslError
import android.os.Build
import android.webkit.RenderProcessGoneDetail
import android.webkit.SslErrorHandler
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.annotation.RequiresApi
import com.tencent.qian.webview.model.SdkEvent
import com.tencent.qian.webview.model.SignCallback
import com.tencent.qian.webview.scheme.ExternalSchemeHandler
import com.tencent.qian.webview.scheme.SchemeInterceptor

/**
 * SDK 内置 WebViewClient。
 *
 * **拦截优先级**:
 * 1. `qianapp://` → [SchemeInterceptor] 解析 → 回调 + cancel
 * 2. `http(s)://` → 默认导航(`return false`)
 * 3. `externalSchemes` 白名单 → 系统 Intent(无论启动成功失败,本次都消费)
 * 4. 未知 scheme → 丢弃 + [SdkEvent.SchemeNotMatched]
 *
 * **错误事件**:`onReceivedError` / `onReceivedHttpError` 仅主框架上报。
 *
 * **SSL 错误**:永远 [SslErrorHandler.cancel] + 上报 [SdkEvent.SslError],绝不 proceed。
 *
 * 与 iOS `QianNavigationDelegate.swift` 1:1 对齐。
 */
internal class QianWebViewClient(
    private val schemeInterceptor: SchemeInterceptor,
    private val externalSchemeHandler: ExternalSchemeHandler,
    private val callbackProvider: () -> SignCallback?,
    private val contextProvider: () -> Context?
) : WebViewClient() {

    // ────────── shouldOverrideUrlLoading ──────────

    @RequiresApi(Build.VERSION_CODES.N)
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
        return overrideUrl(request?.url?.toString())
    }

    @Deprecated("for API < 24")
    @Suppress("OverridingDeprecatedMember")
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        return overrideUrl(url)
    }

    private fun overrideUrl(url: String?): Boolean {
        if (url.isNullOrEmpty()) return false

        // 1. qianapp://
        if (schemeInterceptor.handle(url)) return true

        // 2. http(s) 走默认
        val lower = url.lowercase()
        if (lower.startsWith("http://") || lower.startsWith("https://")) return false

        // 3 & 4. external + 兜底
        val ctx = contextProvider() ?: return false
        return externalSchemeHandler.tryStartActivity(ctx, url)
    }

    // ────────── 生命周期 ──────────

    override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
        callbackProvider()?.onEvent(SdkEvent.PageStarted(url.orEmpty()))
    }

    override fun onPageFinished(view: WebView?, url: String?) {
        callbackProvider()?.onEvent(SdkEvent.PageFinished(url.orEmpty()))
    }

    // ────────── 错误事件(仅主框架) ──────────

    @RequiresApi(Build.VERSION_CODES.M)
    override fun onReceivedError(
        view: WebView?,
        request: WebResourceRequest?,
        error: WebResourceError?
    ) {
        if (request?.isForMainFrame != true) return
        callbackProvider()?.onEvent(
            SdkEvent.LoadError(
                url = request.url?.toString().orEmpty(),
                errorCode = error?.errorCode ?: 0,
                description = error?.description?.toString().orEmpty()
            )
        )
    }

    @Deprecated("for API < 23")
    @Suppress("OverridingDeprecatedMember", "DEPRECATION")
    override fun onReceivedError(
        view: WebView?,
        errorCode: Int,
        description: String?,
        failingUrl: String?
    ) {
        // API < 23 没法判断是否主框架,保守上报
        callbackProvider()?.onEvent(
            SdkEvent.LoadError(failingUrl.orEmpty(), errorCode, description.orEmpty())
        )
    }

    @RequiresApi(Build.VERSION_CODES.M)
    override fun onReceivedHttpError(
        view: WebView?,
        request: WebResourceRequest?,
        errorResponse: WebResourceResponse?
    ) {
        if (request?.isForMainFrame != true) return
        callbackProvider()?.onEvent(
            SdkEvent.HttpError(
                url = request.url?.toString().orEmpty(),
                statusCode = errorResponse?.statusCode ?: 0,
                reasonPhrase = errorResponse?.reasonPhrase.orEmpty()
            )
        )
    }

    override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
        // 永远 cancel,绝不 proceed
        handler?.cancel()
        callbackProvider()?.onEvent(
            SdkEvent.SslError(
                url = error?.url.orEmpty(),
                primaryError = error?.primaryError ?: -1
            )
        )
    }

    // ────────── 渲染进程崩溃恢复(Android 8.0+ / API 26+) ──────────

    /**
     * WebView 渲染进程崩溃或被系统杀死时回调。
     *
     * **背景**:Android 8.0+ 多进程 WebView 架构下,渲染进程可能因 OOM、GPU 驱动异常
     * 或系统资源回收而被杀死。如果不处理:
     * - 不返回 `true` → 系统会直接杀死宿主 Activity(Android 8.0 默认行为)
     * - 返回 `true` 但不处理 → WebView 白屏,用户无感知
     *
     * **策略**:上报事件,由容器层(Activity)决定是否 reload 或 finish。
     * 当前实现:返回 `true` 阻止系统杀 Activity,并上报 [SdkEvent.RenderProcessGone]。
     *
     * **OEM 差异**:
     * - 低端设备(2GB RAM Android Go)概率较高
     * - 华为 EMUI 部分版本在后台切前台时更容易触发
     * - 三星 One UI 4.x 在 WebGL 重度页面上偶发
     */
    @RequiresApi(Build.VERSION_CODES.O)
    override fun onRenderProcessGone(view: WebView?, detail: RenderProcessGoneDetail?): Boolean {
        val didCrash = detail?.didCrash() ?: true
        callbackProvider()?.onEvent(
            SdkEvent.RenderProcessGone(
                didCrash = didCrash,
                url = view?.url.orEmpty()
            )
        )
        // 返回 true 阻止系统杀死宿主 Activity;
        // 容器层通过监听 RenderProcessGone 事件决定后续处理(reload / finish)
        return true
    }
}
