#import "TQManifestStore.h"
#import "TQHTTPHeaderCompat.h"

/// pending 回调队列上限。弱网下 ensureFresh 可能多次入队，设上限防御异常累积。
static const NSUInteger kMaxPending = 16;

@implementation TQManifestStore {
    TQWarmupManifest *_manifest;
    NSTimeInterval _lastFetchAt;
    NSTimeInterval _ttl;
    NSString *_manifestUrl;
    BOOL _isFetching;
    NSMutableArray<TQManifestReadyBlock> *_pending;
    NSObject *_lock;
}

- (instancetype)init {
    if (self = [super init]) {
        _manifest = nil;
        _lastFetchAt = 0;
        _ttl = 300;
        _manifestUrl = @"";
        _isFetching = NO;
        _pending = [NSMutableArray array];
        _lock = [[NSObject alloc] init];
    }
    return self;
}

- (void)setManifestUrl:(NSString *)url {
    @synchronized (_lock) { _manifestUrl = [url copy] ?: @""; }
}

- (nullable TQWarmupManifest *)currentManifest {
    @synchronized (_lock) { return _manifest; }
}

- (BOOL)isStale {
    @synchronized (_lock) {
        return ([[NSDate date] timeIntervalSince1970] - _lastFetchAt) > _ttl;
    }
}

- (void)ensureFresh:(nullable TQManifestReadyBlock)onReady {
    TQWarmupManifest *current;
    BOOL stale;
    @synchronized (_lock) {
        current = _manifest;
        stale = ([[NSDate date] timeIntervalSince1970] - _lastFetchAt) > _ttl;
        if (current == nil && onReady != nil) {
            // 上限保护：超限直接丢弃新回调，避免弱网下 pending 无界增长。
            if (_pending.count < kMaxPending) {
                [_pending addObject:[onReady copy]];
            }
        }
    }
    if (current != nil) {
        if (onReady != nil) {
            onReady(current);
        }
        if (stale) {
            [self fetch];
        }
        return;
    }
    [self fetch];
}

- (void)fetch {
    NSString *url;
    @synchronized (_lock) {
        url = _manifestUrl;
        if (url.length == 0 || _isFetching) {
            return;
        }
        _isFetching = YES;
    }
    NSURL *u = [NSURL URLWithString:url];
    if (u == nil) {
        @synchronized (_lock) { _isFetching = NO; }
        return;
    }
    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:u];
    req.HTTPMethod = @"GET";
    [req setValue:@"application/json" forHTTPHeaderField:@"Accept"];
    req.timeoutInterval = 8;

    __weak __typeof(self) weakSelf = self;
    NSURLSessionDataTask *task = [[NSURLSession sharedSession]
        dataTaskWithRequest:req
          completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        __strong __typeof(weakSelf) self = weakSelf;
        if (!self) return;
        TQWarmupManifest *parsed = nil;
        NSTimeInterval newTtl = 300;
        if (error == nil && [response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSHTTPURLResponse *http = (NSHTTPURLResponse *)response;
            if (http.statusCode == 200 && data != nil) {
                parsed = [TQWarmupManifest parse:data];
                NSString *cc = [TQHTTPHeaderCompat valueForHeaderField:@"Cache-Control" inResponse:response];
                NSNumber *maxAge = [TQManifestStore parseMaxAge:cc];
                if (maxAge != nil) { newTtl = maxAge.doubleValue; }
            }
        }
        if (parsed == nil) {
            // 拉取失败：清空 pending（符合"失败静默不回调"契约），避免回调无界累积。
            // 下次 prewarm 会重新入队重试；dedup 未 markDone 故不会误判已预热。
            @synchronized (self->_lock) {
                self->_isFetching = NO;
                [self->_pending removeAllObjects];
            }
            return;
        }
        NSArray<TQManifestReadyBlock> *callbacks;
        BOOL versionChanged;
        @synchronized (self->_lock) {
            NSString *oldVersion = self->_manifest ? self->_manifest.version : @"";
            versionChanged = oldVersion.length > 0 && ![oldVersion isEqualToString:parsed.version];
            self->_manifest = parsed;
            self->_ttl = newTtl;
            self->_lastFetchAt = [[NSDate date] timeIntervalSince1970];
            callbacks = [self->_pending copy];
            [self->_pending removeAllObjects];
            self->_isFetching = NO;
        }
        for (TQManifestReadyBlock cb in callbacks) {
            cb(parsed);
        }
        if (versionChanged && self.onVersionChanged) {
            self.onVersionChanged();
        }
    }];
    [task resume];
}

+ (nullable NSNumber *)parseMaxAge:(nullable NSString *)headerValue {
    if (headerValue.length == 0) {
        return nil;
    }
    NSString *cc = [headerValue lowercaseString];
    NSRange r = [cc rangeOfString:@"max-age="];
    if (r.location == NSNotFound) {
        return nil;
    }
    NSString *rest = [cc substringFromIndex:r.location + r.length];
    NSString *token = [[rest componentsSeparatedByString:@","] firstObject];
    token = [token stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
    NSInteger seconds = [token integerValue];
    if (seconds <= 0) {
        return nil;
    }
    return @((NSTimeInterval)seconds);
}

@end
