import Foundation

/// `qianapp://` 协议解析器,与 Android `SignResultParser` 1:1 对齐。
///
/// **解析约定**:
/// - 重复 key 取**首个**(后续覆盖丢弃)
/// - 空 value(`?action=`)保留为空字符串而非 `nil`
/// - 未知 action / result 值**原样透出**,不映射到 UNKNOWN
/// - 非法 URL / scheme 不匹配 → 返回 ``SignResult/empty``
/// - `errorCode` / `errorMsg` 等历史字段 → 落入 ``SignResult/extras``(向前兼容)
///
/// **不依赖 URLComponents 的全部行为**:
/// `URLComponents.queryItems` 在某些 iOS 版本对 `?key=` 的空 value 行为不一致,
/// 此处用手写 query parser,与 Android 端逐字节对齐。
public enum SignResultParser {

    private static let scheme: String = "qianapp"
    private static let schemePrefix: String = "qianapp://"
    private static let recognizedKeys: Set<String> = ["flowId", "action", "result", "from"]

    /// URL 最大长度限制(8KB),超过视为恶意构造,返回 ``SignResult/empty`` 并丢弃。
    private static let maxURLLength = 8 * 1024

    /// 判断 URL 是否为本 SDK 关心的 `qianapp://` scheme(仅看前缀,不严格校验合法性)。
    public static func isQianAppScheme(_ url: String?) -> Bool {
        guard let s = url, !s.isEmpty else { return false }
        return s.lowercased().hasPrefix(schemePrefix)
    }

    /// 解析 `qianapp://...` URL。失败返回 ``SignResult/empty``。
    public static func parse(_ url: String?) -> SignResult {
        guard let url = url, !url.isEmpty else { return .empty }
        guard isQianAppScheme(url) else { return .empty }
        // 防御超长 URL(可能导致内存压力):超过 8KB 直接丢弃
        guard url.count <= maxURLLength else { return .empty }

        // 拆 scheme://body[?query]
        let body = String(url.dropFirst(schemePrefix.count))
        let (pathPart, queryPart) = splitOnce(body, on: "?")

        // host + path 即 customPath。trim 前后斜杠,与 Android 一致。
        let customPath = pathPart.trimmingCharacters(in: CharacterSet(charactersIn: "/"))

        let parsed = parseQuery(queryPart)

        var extras: [String: String] = [:]
        for (k, v) in parsed where !recognizedKeys.contains(k) {
            extras[k] = v
        }

        return SignResult(
            rawUrl: url,
            customPath: customPath,
            flowId: parsed["flowId"] ?? "",
            action: parsed["action"] ?? "",
            result: parsed["result"] ?? "",
            from: parsed["from"] ?? "",
            extras: extras
        )
    }

    // MARK: - 内部工具

    /// 在第一个分隔符上拆分,返回 (左, 右);无分隔符则右半为空字符串。
    private static func splitOnce(_ input: String, on delimiter: Character) -> (String, String) {
        guard let idx = input.firstIndex(of: delimiter) else { return (input, "") }
        let left = String(input[input.startIndex..<idx])
        let right = String(input[input.index(after: idx)...])
        return (left, right)
    }

    /// 解析 query 字符串,UTF-8 percent-decoded,重复 key 保留首个。
    /// 用 `OrderedDict-like` 行为:遍历顺序保留插入顺序,便于跨端测试断言一致。
    private static func parseQuery(_ query: String) -> [String: String] {
        // 注:Swift Dictionary 无序;为保留首次插入的胜出语义,这里 [String: String] 即可
        // (我们只关心「首次出现的 value 胜出」这条规则)
        var out: [String: String] = [:]
        guard !query.isEmpty else { return out }

        let pairs = query.split(separator: "&", omittingEmptySubsequences: false)
        for pair in pairs {
            if pair.isEmpty { continue }
            let (rawKey, rawValue) = splitOnce(String(pair), on: "=")
            guard let key = decode(rawKey) else { continue }
            if key.isEmpty { continue }
            if out[key] != nil { continue } // 重复 key 保留首个
            let value = decode(rawValue) ?? ""
            out[key] = value
        }
        return out
    }

    /// UTF-8 percent-decoding。`+` 等价于空格,与 application/x-www-form-urlencoded 一致。
    private static func decode(_ raw: String) -> String? {
        // 与 Android `URLDecoder.decode(_, "UTF-8")` 行为对齐:`+` → 空格
        let plusReplaced = raw.replacingOccurrences(of: "+", with: " ")
        return plusReplaced.removingPercentEncoding
    }
}
