package com.tencent.qian.webview.client

import android.content.Context
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.tencent.qian.webview.model.SdkEvent
import com.tencent.qian.webview.model.SignCallback
import com.tencent.qian.webview.model.SignResult
import com.tencent.qian.webview.scheme.ExternalSchemeHandler
import com.tencent.qian.webview.scheme.SchemeInterceptor
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RuntimeEnvironment

/**
 * [QianWebViewClient] 的 URL 路由优先级单测。
 *
 * 覆盖 `overrideUrl()` 的 4 级优先级调度逻辑:
 * 1. qianapp:// → SchemeInterceptor 拦截 → return true
 * 2. http(s):// → 放行 → return false
 * 3. externalSchemes 白名单命中 → Intent 启动 → return true
 * 4. 未知 scheme → SchemeNotMatched → return true
 * + null/空 → return false
 * + context 为 null → return false
 */
@RunWith(AndroidJUnit4::class)
class QianWebViewClientOverrideUrlTest {

    private lateinit var context: Context
    private val events = mutableListOf<SdkEvent>()
    private val signResults = mutableListOf<SignResult>()
    private val callback = object : SignCallback {
        override fun onSignResult(result: SignResult) {
            signResults.add(result)
        }
        override fun onEvent(event: SdkEvent) {
            events.add(event)
        }
    }

    @Before
    fun setUp() {
        context = RuntimeEnvironment.getApplication()
        events.clear()
        signResults.clear()
    }

    private fun createClient(
        externalSchemes: List<String> = listOf("weixin", "alipays"),
        contextProvider: () -> Context? = { context }
    ): QianWebViewClient {
        val schemeInterceptor = SchemeInterceptor { callback }
        val externalSchemeHandler = ExternalSchemeHandler(externalSchemes) { callback }
        return QianWebViewClient(
            schemeInterceptor = schemeInterceptor,
            externalSchemeHandler = externalSchemeHandler,
            callbackProvider = { callback },
            contextProvider = contextProvider
        )
    }

    // ────────── 优先级 1: qianapp:// → 拦截 ──────────

    @Test
    fun `qianapp URL is intercepted and returns true`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "qianapp://callback/sign?action=sign&result=success&flowId=abc")

        assertTrue("qianapp 应被拦截", result)
        // SchemeInterceptor 会派发 onSignResult
        assertTrue(signResults.isNotEmpty())
    }

    @Test
    fun `qianapp with uppercase scheme is intercepted`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "QIANAPP://x?action=fill")

        assertTrue(result)
    }

    // ────────── 优先级 2: http(s) → 放行 ──────────

    @Test
    fun `http URL returns false - allows default navigation`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "http://example.com/page")

        assertFalse("http 应放行", result)
        assertTrue(events.isEmpty())
    }

    @Test
    fun `https URL returns false - allows default navigation`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "https://quick.qian.tencent.cn/sign")

        assertFalse("https 应放行", result)
        assertTrue(events.isEmpty())
    }

    @Test
    fun `HTTPS uppercase returns false`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "HTTPS://EXAMPLE.COM/PATH")

        assertFalse(result)
    }

    // ────────── 优先级 3: externalSchemes 白名单 → 消费 ──────────

    @Test
    fun `weixin URL in whitelist is consumed`() {
        val client = createClient(externalSchemes = listOf("weixin", "alipays"))
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "weixin://wxa/launchminiprogram?appid=wx123")

        assertTrue("weixin 应被消费", result)
        assertEquals(1, events.size)
        assertTrue(events[0] is SdkEvent.SchemeIntercepted)
    }

    @Test
    fun `alipays URL in whitelist is consumed`() {
        val client = createClient(externalSchemes = listOf("weixin", "alipays"))
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "alipays://platformapi/startapp?appId=123")

        assertTrue(result)
        assertTrue(events.any { it is SdkEvent.SchemeIntercepted })
    }

    // ────────── 优先级 4: 未知 scheme → SchemeNotMatched ──────────

    @Test
    fun `unknown scheme not in whitelist emits SchemeNotMatched`() {
        val client = createClient(externalSchemes = listOf("weixin", "alipays"))
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "mqqapi://chat?uin=12345")

        assertTrue("未知 scheme 应被消费(丢弃)", result)
        assertEquals(1, events.size)
        assertTrue(events[0] is SdkEvent.SchemeNotMatched)
    }

    // ────────── 边界: null / 空 → return false ──────────

    @Test
    fun `null URL returns false`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, null as String?)

        assertFalse(result)
        assertTrue(events.isEmpty())
    }

    @Test
    fun `empty URL returns false`() {
        val client = createClient()
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "")

        assertFalse(result)
        assertTrue(events.isEmpty())
    }

    // ────────── 边界: context 为 null → return false ──────────

    @Test
    fun `null context returns false for external scheme`() {
        val client = createClient(
            externalSchemes = listOf("weixin"),
            contextProvider = { null }
        )
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "weixin://wxa/test")

        // context 为 null,无法启动 Intent,返回 false
        assertFalse(result)
    }

    // ────────── 优先级验证: qianapp 优先于 externalSchemes ──────────

    @Test
    fun `qianapp takes priority even if also in externalSchemes`() {
        // 即使 externalSchemes 包含 qianapp(不应该,但防御性测试)
        val client = createClient(externalSchemes = listOf("qianapp", "weixin"))
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "qianapp://callback?action=sign&result=success")

        assertTrue(result)
        // 应该走 SchemeInterceptor 而非 ExternalSchemeHandler
        assertTrue(signResults.isNotEmpty())
    }

    // ────────── http 优先于 externalSchemes ──────────

    @Test
    fun `http takes priority even if also in externalSchemes`() {
        // 即使 externalSchemes 包含 http(不应该,但防御性测试)
        val client = createClient(externalSchemes = listOf("http", "weixin"))
        @Suppress("DEPRECATION")
        val result = client.shouldOverrideUrlLoading(null as android.webkit.WebView?, "http://example.com")

        assertFalse("http 应放行,不走 externalSchemes", result)
    }
}
