package com.tencent.qian.webview.scheme

import com.tencent.qian.webview.model.SignAction
import com.tencent.qian.webview.model.SignResult
import com.tencent.qian.webview.model.SignResultStatus
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertSame
import org.junit.Assert.assertTrue
import org.junit.Test

/**
 * [SignResultParser] 单测。
 *
 * 覆盖场景:
 * - 标准
 * - 空字段
 * - 未知 action 原样透出
 * - 重复 key
 * - 非法 URL
 * - extras 透传
 * - errorCode 落 extras
 * - 中文 percent decode
 * - SignAction.SIGN 常量比较
 *
 * 同一组用例在 iOS `SignResultParserTests.swift` 同步覆盖。
 */
class SignResultParserTest {

    // ────────── 1. 标准签署成功 ──────────

    @Test fun parses_standard_sign_success() {
        val url = "qianapp://callback/sign" +
            "?flowId=abc-123&action=sign&result=success&from=tencent_ess"
        val r = SignResultParser.parse(url)

        assertEquals(url, r.rawUrl)
        assertEquals("callback/sign", r.customPath)
        assertEquals("abc-123", r.flowId)
        assertEquals(SignAction.SIGN, r.action)
        assertEquals(SignResultStatus.SUCCESS, r.result)
        assertEquals("tencent_ess", r.from)
        assertTrue(r.extras.isEmpty())
    }

    // ────────── 2. 空字段(?action= 保留为空字符串)──────────

    @Test fun preserves_empty_value_as_empty_string() {
        val url = "qianapp://x?flowId=&action=&result=&from="
        val r = SignResultParser.parse(url)

        assertEquals("", r.flowId)
        assertEquals("", r.action)
        assertEquals("", r.result)
        assertEquals("", r.from)
    }

    // ────────── 3. 未知 action 原样透出(不映射 UNKNOWN)──────────

    @Test fun preserves_unknown_action_value_verbatim() {
        val url = "qianapp://x?action=futureBrandNewAction&result=mystery"
        val r = SignResultParser.parse(url)

        assertEquals("futureBrandNewAction", r.action)
        assertEquals("mystery", r.result)
        // 客户在 when 的 else 分支可以拿到原值
        assertFalse(r.action == SignAction.SIGN)
    }

    // ────────── 4. 重复 key 取首个 ──────────

    @Test fun keeps_first_value_when_query_key_duplicates() {
        val url = "qianapp://x?flowId=first&flowId=second&action=sign"
        val r = SignResultParser.parse(url)

        assertEquals("first", r.flowId)
        assertEquals(SignAction.SIGN, r.action)
    }

    // ────────── 5. 非法 URL → EMPTY ──────────

    @Test fun returns_EMPTY_for_null_or_empty_or_wrong_scheme() {
        assertSame(SignResult.EMPTY, SignResultParser.parse(null))
        assertSame(SignResult.EMPTY, SignResultParser.parse(""))
        assertSame(SignResult.EMPTY, SignResultParser.parse("https://example.com/x"))
        assertSame(SignResult.EMPTY, SignResultParser.parse("weixin://wap/pay"))
    }

    // ────────── 6. extras 透传 ──────────

    @Test fun transfers_unknown_query_keys_to_extras() {
        val url = "qianapp://done" +
            "?flowId=f1&action=sign&result=success" +
            "&customer_id=u-42&channel=ad-banner"
        val r = SignResultParser.parse(url)

        assertEquals(mapOf("customer_id" to "u-42", "channel" to "ad-banner"), r.extras)
        assertEquals("f1", r.flowId) // recognized field 不重复进 extras
        assertFalse(r.extras.containsKey("flowId"))
    }

    // ────────── 7. errorCode 历史字段落 extras(向前兼容)──────────

    @Test fun keeps_errorCode_and_errorMsg_in_extras() {
        val url = "qianapp://x" +
            "?action=sign&result=fail" +
            "&errorCode=10086&errorMsg=user_canceled"
        val r = SignResultParser.parse(url)

        assertEquals(SignResultStatus.FAIL, r.result)
        assertEquals("10086", r.extras["errorCode"])
        assertEquals("user_canceled", r.extras["errorMsg"])
    }

    // ────────── 8. 中文 percent-decode ──────────

    @Test fun decodes_utf8_percent_encoded_chinese() {
        // "签署成功" UTF-8 percent-encoded
        val url = "qianapp://x?action=sign&note=%E7%AD%BE%E7%BD%B2%E6%88%90%E5%8A%9F"
        val r = SignResultParser.parse(url)

        assertEquals("签署成功", r.extras["note"])
    }

    // ────────── 9. customPath = host + path ──────────

    @Test fun customPath_combines_host_and_path() {
        val r1 = SignResultParser.parse("qianapp://callback/sign?flowId=1")
        assertEquals("callback/sign", r1.customPath)

        val r2 = SignResultParser.parse("qianapp://result?flowId=1")
        assertEquals("result", r2.customPath)

        val r3 = SignResultParser.parse("qianapp://done/")
        assertEquals("done", r3.customPath)
    }

    // ────────── 10. 无 query ──────────

    @Test fun parses_url_without_query() {
        val r = SignResultParser.parse("qianapp://done")
        assertEquals("done", r.customPath)
        assertEquals("", r.flowId)
        assertTrue(r.extras.isEmpty())
    }

    // ────────── 11. 等号 in value ──────────

    @Test fun preserves_equal_sign_inside_value() {
        // base64 之类 value 含等号
        val url = "qianapp://x?token=abc==&action=sign"
        val r = SignResultParser.parse(url)

        assertEquals("abc==", r.extras["token"])
        assertEquals(SignAction.SIGN, r.action)
    }

    // ────────── 12. 大小写 scheme ──────────

    @Test fun accepts_uppercase_scheme() {
        val r = SignResultParser.parse("QIANAPP://x?action=sign")
        assertEquals(SignAction.SIGN, r.action)
    }

    // ────────── 13. SignAction / SignResultStatus 常量比对(防漂移)──────────

    @Test fun constants_match_protocol_wire_values() {
        assertEquals("fill", SignAction.FILL)
        assertEquals("sign", SignAction.SIGN)
        assertEquals("reject_fill", SignAction.REJECT_FILL)
        assertEquals("reject_sign", SignAction.REJECT_SIGN)
        assertEquals("view", SignAction.VIEW)

        assertEquals("success", SignResultStatus.SUCCESS)
        assertEquals("fail", SignResultStatus.FAIL)
    }
}
