// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { mergeHeaders, getInitialHeader } from "./headerUtils.js";
import { ContinuationTokenManagerFactory } from "./ContinuationTokenManager/ContinuationTokenManagerFactory.js";
import { Constants } from "../common/index.js";
/**
 * Query control enabled fetch implementation with continuation token support
 * @hidden
 */
export class QueryControlFetchImplementation {
    endpoint;
    pageSize;
    // Required fields for query control - not optional
    continuationTokenManager;
    querySupportsTokens;
    constructor(endpoint, pageSize, collectionLink, continuationToken, isOrderByQuery, querySupportsTokens) {
        this.endpoint = endpoint;
        this.pageSize = pageSize;
        this.querySupportsTokens = querySupportsTokens;
        // Initialize continuation token manager immediately for query control
        this.continuationTokenManager = ContinuationTokenManagerFactory.create(collectionLink, continuationToken, isOrderByQuery);
    }
    async fetchMore(diagnosticNode, fetchBuffer) {
        // Initialize headers fresh for each fetchMore call
        const fetchMoreRespHeaders = getInitialHeader();
        // Use continuation token logic for supported queries when query control is enabled
        // Otherwise use simplified buffer-only logic
        if (this.querySupportsTokens) {
            return this._handleQueryFetch(diagnosticNode, fetchBuffer, fetchMoreRespHeaders);
        }
        else {
            return this._handleSimpleBufferFetch(diagnosticNode, fetchBuffer, fetchMoreRespHeaders);
        }
    }
    async _handleSimpleBufferFetch(diagnosticNode, fetchBuffer, fetchMoreRespHeaders) {
        // Return buffered data if available
        if (fetchBuffer.length > 0) {
            const temp = fetchBuffer.slice(0, this.pageSize);
            fetchBuffer.splice(0, this.pageSize); // Remove items in place
            return { result: temp, headers: fetchMoreRespHeaders };
        }
        // Fetch new data from endpoint
        const response = await this.endpoint.fetchMore(diagnosticNode);
        mergeHeaders(fetchMoreRespHeaders, response.headers);
        if (!response?.result?.buffer?.length) {
            return this._createEmptyResult(response?.headers);
        }
        // Buffer new data and return up to pageSize
        fetchBuffer.length = 0; // Clear existing items
        fetchBuffer.push(...response.result.buffer); // Add new items
        const temp = fetchBuffer.slice(0, this.pageSize);
        fetchBuffer.splice(0, this.pageSize); // Remove returned items in place
        return { result: temp, headers: fetchMoreRespHeaders };
    }
    async _handleQueryFetch(diagnosticNode, fetchBuffer, fetchMoreRespHeaders) {
        if (fetchBuffer.length > 0) {
            const { endIndex, continuationToken } = this.continuationTokenManager.paginateResults(this.pageSize, false);
            const temp = fetchBuffer.slice(0, endIndex);
            fetchBuffer.splice(0, endIndex); // Remove returned items in place
            this._setContinuationTokenInHeaders(continuationToken, fetchMoreRespHeaders);
            return { result: temp, headers: fetchMoreRespHeaders };
        }
        // Fetch new data from endpoint
        fetchBuffer.length = 0; // Clear existing items in place
        const response = await this.endpoint.fetchMore(diagnosticNode);
        mergeHeaders(fetchMoreRespHeaders, response.headers);
        if (!response?.result?.buffer || response.result.buffer.length === 0) {
            const { continuationToken } = this.continuationTokenManager.paginateResults(this.pageSize, true, // isResponseEmpty = true
            response?.result);
            this._setContinuationTokenInHeaders(continuationToken, fetchMoreRespHeaders);
            return this._createEmptyResult(fetchMoreRespHeaders);
        }
        fetchBuffer.push(...response.result.buffer); // Add new items to existing buffer
        const { endIndex, continuationToken } = this.continuationTokenManager.paginateResults(this.pageSize, false, // isResponseEmpty = false
        response.result);
        const temp = fetchBuffer.slice(0, endIndex);
        fetchBuffer.splice(0, endIndex); // Remove returned items in place
        this._setContinuationTokenInHeaders(continuationToken, fetchMoreRespHeaders);
        return { result: temp, headers: fetchMoreRespHeaders };
    }
    _setContinuationTokenInHeaders(continuationToken, fetchMoreRespHeaders) {
        if (continuationToken) {
            Object.assign(fetchMoreRespHeaders, {
                [Constants.HttpHeaders.Continuation]: continuationToken,
            });
        }
    }
    _createEmptyResult(headers) {
        const hdrs = headers || getInitialHeader();
        return { result: [], headers: hdrs };
    }
}
//# sourceMappingURL=QueryControlFetchImplementation.js.map