package com.tencent.qian.webview.scheme;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.tencent.qian.webview.model.SignResult;

import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * {@code qianapp://} 协议解析器。
 */
public final class SignResultParser {

    private static final String SCHEME = "qianapp";
    private static final String SCHEME_PREFIX = SCHEME + "://";
    private static final int MAX_URL_LENGTH = 8 * 1024;
    private static final Set<String> RECOGNIZED_KEYS = new HashSet<>(Arrays.asList("flowId", "action", "result", "from"));

    private SignResultParser() {}

    public static boolean isQianAppScheme(@Nullable String url) {
        if (url == null || url.isEmpty()) return false;
        return url.regionMatches(true, 0, SCHEME_PREFIX, 0, SCHEME_PREFIX.length());
    }

    @NonNull
    public static SignResult parse(@Nullable String url) {
        if (url == null || url.isEmpty()) return SignResult.EMPTY;
        if (!isQianAppScheme(url)) return SignResult.EMPTY;
        if (url.length() > MAX_URL_LENGTH) return SignResult.EMPTY;

        String body = url.substring(SCHEME_PREFIX.length());
        int qIdx = body.indexOf('?');
        String pathPart;
        String queryPart;
        if (qIdx < 0) {
            pathPart = body;
            queryPart = "";
        } else {
            pathPart = body.substring(0, qIdx);
            queryPart = body.substring(qIdx + 1);
        }

        // 去首尾 /
        String customPath = pathPart;
        while (customPath.startsWith("/")) customPath = customPath.substring(1);
        while (customPath.endsWith("/")) customPath = customPath.substring(0, customPath.length() - 1);

        LinkedHashMap<String, String> parsed = parseQuery(queryPart);

        String flowId = parsed.containsKey("flowId") ? parsed.get("flowId") : "";
        String action = parsed.containsKey("action") ? parsed.get("action") : "";
        String result = parsed.containsKey("result") ? parsed.get("result") : "";
        String from = parsed.containsKey("from") ? parsed.get("from") : "";

        LinkedHashMap<String, String> extras = new LinkedHashMap<>();
        for (Map.Entry<String, String> entry : parsed.entrySet()) {
            if (!RECOGNIZED_KEYS.contains(entry.getKey())) {
                extras.put(entry.getKey(), entry.getValue());
            }
        }

        return new SignResult(url, customPath, flowId, action, result, from, extras);
    }

    @NonNull
    private static LinkedHashMap<String, String> parseQuery(@NonNull String query) {
        LinkedHashMap<String, String> out = new LinkedHashMap<>();
        if (query.isEmpty()) return out;

        for (String pair : query.split("&")) {
            if (pair.isEmpty()) continue;
            int eqIdx = pair.indexOf('=');
            String rawKey;
            String rawValue;
            if (eqIdx < 0) {
                rawKey = pair;
                rawValue = "";
            } else {
                rawKey = pair.substring(0, eqIdx);
                rawValue = pair.substring(eqIdx + 1);
            }
            String key = decodeOrNull(rawKey);
            if (key == null || key.isEmpty()) continue;
            if (out.containsKey(key)) continue;
            String value = decodeOrNull(rawValue);
            if (value == null) value = "";
            out.put(key, value);
        }
        return out;
    }

    @Nullable
    private static String decodeOrNull(@NonNull String raw) {
        try {
            return URLDecoder.decode(raw, "UTF-8");
        } catch (Exception e) {
            return null;
        }
    }
}
