#import "TQSignResultParser.h"

static NSString *const kSchemePrefix = @"qianapp://";
/// URL 最大长度限制(8KB),超过视为恶意构造,丢弃。
static const NSUInteger kMaxURLLength = 8 * 1024;

@implementation TQSignResultParser

+ (NSSet<NSString *> *)recognizedKeys {
    static NSSet *keys;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        keys = [NSSet setWithObjects:@"flowId", @"action", @"result", @"from", nil];
    });
    return keys;
}

+ (BOOL)isQianAppScheme:(NSString *)urlString {
    if (urlString.length == 0) return NO;
    return [[urlString lowercaseString] hasPrefix:kSchemePrefix];
}

+ (TQSignResult *)parse:(NSString *)urlString {
    if (urlString.length == 0) return [TQSignResult empty];
    if (![self isQianAppScheme:urlString]) return [TQSignResult empty];
    // 防御超长 URL(可能导致内存压力):超过 8KB 直接丢弃
    if (urlString.length > kMaxURLLength) return [TQSignResult empty];

    // 拆 scheme://body[?query]
    NSString *body = [urlString substringFromIndex:kSchemePrefix.length];
    NSString *pathPart;
    NSString *queryPart;
    [self splitOnce:body delimiter:'?' left:&pathPart right:&queryPart];

    // host + path 即 customPath。trim 前后斜杠,与 Android / Swift 一致。
    NSString *customPath = [pathPart stringByTrimmingCharactersInSet:
                            [NSCharacterSet characterSetWithCharactersInString:@"/"]];

    NSDictionary<NSString *, NSString *> *parsed = [self parseQuery:queryPart];

    NSSet *recognized = [self recognizedKeys];
    NSMutableDictionary<NSString *, NSString *> *extras = [NSMutableDictionary dictionary];
    for (NSString *k in parsed) {
        if (![recognized containsObject:k]) {
            extras[k] = parsed[k];
        }
    }

    return [[TQSignResult alloc] initWithRawUrl:urlString
                                     customPath:customPath
                                         flowId:parsed[@"flowId"] ?: @""
                                         action:parsed[@"action"] ?: @""
                                         result:parsed[@"result"] ?: @""
                                           from:parsed[@"from"]   ?: @""
                                         extras:extras];
}

#pragma mark - 内部工具

/// 在第一个分隔符上拆分,返回 (左, 右);无分隔符则右半为空字符串。
+ (void)splitOnce:(NSString *)input
        delimiter:(unichar)delimiter
             left:(NSString **)outLeft
            right:(NSString **)outRight {
    NSRange range = [input rangeOfString:[NSString stringWithCharacters:&delimiter length:1]];
    if (range.location == NSNotFound) {
        *outLeft = input;
        *outRight = @"";
        return;
    }
    *outLeft = [input substringToIndex:range.location];
    *outRight = [input substringFromIndex:range.location + 1];
}

/// 解析 query 字符串,UTF-8 percent-decoded,重复 key 保留首个。
+ (NSDictionary<NSString *, NSString *> *)parseQuery:(NSString *)query {
    NSMutableDictionary<NSString *, NSString *> *out = [NSMutableDictionary dictionary];
    if (query.length == 0) return out;

    // 保留所有空 token(包括空 pair),便于"?action=" 这类空 value 也被收录
    NSArray<NSString *> *pairs = [query componentsSeparatedByString:@"&"];
    for (NSString *pair in pairs) {
        if (pair.length == 0) continue;
        NSString *rawKey, *rawValue;
        [self splitOnce:pair delimiter:'=' left:&rawKey right:&rawValue];
        NSString *key = [self decode:rawKey];
        if (key == nil || key.length == 0) continue;
        if (out[key] != nil) continue; // 重复 key 保留首个
        NSString *value = [self decode:rawValue] ?: @"";
        out[key] = value;
    }
    return out;
}

/// UTF-8 percent-decoding。`+` 等价于空格,与 application/x-www-form-urlencoded 一致。
+ (nullable NSString *)decode:(NSString *)raw {
    if (raw == nil) return nil;
    // 与 application/x-www-form-urlencoded 一致:`+` → 空格
    NSString *plusReplaced = [raw stringByReplacingOccurrencesOfString:@"+" withString:@" "];
    return [plusReplaced stringByRemovingPercentEncoding];
}

@end
