"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MaximumRetriesReached = exports.sendResultsToServer = exports.MAX_RETRIES = exports.MAX_PAGE_STATES_PER_REQUEST = void 0;
const undici_1 = require("undici");
const readVariables_1 = __importDefault(require("./utils/readVariables"));
const linearBackoff_1 = __importDefault(require("./utils/linearBackoff"));
const isCI_1 = require("./utils/isCI");
const shouldUseEnvProxy_1 = require("./utils/shouldUseEnvProxy");
const saveScreenshotsLocally_1 = require("./utils/saveScreenshotsLocally");
const { version } = require('../package.json');
exports.MAX_PAGE_STATES_PER_REQUEST = 5;
exports.MAX_RETRIES = 3;
const sendResultsToServer = async ({ results, debugLogger }) => {
    const { server_url, api_key, session_id, git_data, screenshot_dir: screenshotDir } = (0, readVariables_1.default)();
    const resultsURL = new URL(`/api-pub/watcher/sessions/${session_id}`, server_url);
    const screenshotsURL = new URL(`/api-pub/watcher/sessions/${session_id}/screenshots`, server_url);
    const isCanonicalSource = (0, isCI_1.isCI)();
    debugLogger('SendResultsToServer: Received results', {
        total: results.length,
        totalBytes: Buffer.byteLength(JSON.stringify(results))
    });
    debugLogger('SendResultsToServer: Session ID', { session_id });
    debugLogger('SendResultsToServer: Is Canonical Source', { isCanonicalSource });
    const putResults = async (bodyResults = [], retryAttempt = 0) => {
        const body = {
            axe_watcher_version: version,
            results: bodyResults,
            is_canonical_source: isCanonicalSource,
            ...git_data
        };
        let dispatcher = (0, undici_1.getGlobalDispatcher)();
        if ((0, shouldUseEnvProxy_1.shouldUseEnvProxy)()) {
            dispatcher = new undici_1.EnvHttpProxyAgent();
        }
        try {
            const res = await (0, undici_1.fetch)(resultsURL, {
                method: 'PUT',
                redirect: 'follow',
                headers: {
                    'Content-Type': 'application/json',
                    'X-API-Key': api_key
                },
                dispatcher,
                body: JSON.stringify(body),
                signal: AbortSignal.timeout(10000)
            });
            if (!res.ok) {
                debugLogger('SendResultsToServer: Failed to send results', {
                    batchResults: bodyResults.length,
                    reqSize: Buffer.byteLength(JSON.stringify(body)),
                    resStatus: res.status,
                    resStatusText: res.statusText
                });
                console.warn('@axe-core/watcher: Unable to send results to server');
            }
            else {
                debugLogger('SendResultsToServer: Successfully sent', {
                    batchResults: bodyResults.length,
                    reqSize: Buffer.byteLength(JSON.stringify(body)),
                    resStatus: res.status,
                    resStatusText: res.statusText
                });
            }
            const is500 = res.status === 500;
            const is408 = res.status === 408;
            const is429 = res.status === 429;
            if ((is500 || is408 || is429) && retryAttempt !== exports.MAX_RETRIES) {
                const incrementRetry = retryAttempt + 1;
                console.warn('@axe-core/watcher: Retrying...');
                debugLogger('SendResultsToServer: Retrying...', {
                    retryAttempt: incrementRetry,
                    resStatus: res.status,
                    batchResults: bodyResults.length,
                    reqSize: Buffer.byteLength(JSON.stringify(body))
                });
                await (0, linearBackoff_1.default)(incrementRetry);
                await putResults(bodyResults, incrementRetry);
            }
            else if (retryAttempt === exports.MAX_RETRIES && !res.ok) {
                debugLogger('SendResultsToServer: Max retries reached', {
                    retryAttempt,
                    resStatus: res.status
                });
                console.warn('@axe-core/watcher: Unable to send results to server, max retries reached');
                return Promise.reject(new MaximumRetriesReached());
            }
        }
        catch (error) {
            if (error.name === 'TimeoutError') {
                debugLogger('SendResultsToServer: Aborted request due to timeout', {
                    abortTimeout: 10000,
                    retryAttempt,
                    batchResults: bodyResults.length,
                    reqSize: Buffer.byteLength(JSON.stringify(body))
                });
                if (retryAttempt !== exports.MAX_RETRIES) {
                    const incrementRetry = retryAttempt + 1;
                    console.warn('@axe-core/watcher: Retrying after timeout...');
                    debugLogger('SendResultsToServer: Retrying after timeout...', {
                        retryAttempt: incrementRetry,
                        batchResults: bodyResults.length,
                        reqSize: Buffer.byteLength(JSON.stringify(body))
                    });
                    await (0, linearBackoff_1.default)(incrementRetry);
                    await putResults(bodyResults, incrementRetry);
                }
                else {
                    debugLogger('SendResultsToServer: Max retries reached after timeout', {
                        retryAttempt
                    });
                    console.warn('@axe-core/watcher: Request timed out, max retries reached');
                    return Promise.reject(new MaximumRetriesReached());
                }
            }
            throw error;
        }
    };
    if (screenshotDir) {
        (0, saveScreenshotsLocally_1.saveScreenshotsLocally)(results, screenshotDir);
    }
    const requestErrorHandler = (error) => {
        if (error instanceof MaximumRetriesReached) {
            return { failureStatus: error.message };
        }
        debugLogger('SendResultsToServer: Fetch error', error);
    };
    let catchResult;
    for (let i = 0; i < results.length; i += exports.MAX_PAGE_STATES_PER_REQUEST) {
        const batch = results
            .slice(i, i + exports.MAX_PAGE_STATES_PER_REQUEST)
            .map(r => ({ ...r, screenshot: null, screenshot_path: undefined }));
        catchResult = await putResults(batch).catch(requestErrorHandler);
        if (catchResult) {
            break;
        }
    }
    if (catchResult) {
        return Promise.resolve(catchResult);
    }
    let dispatcher = (0, undici_1.getGlobalDispatcher)();
    if ((0, shouldUseEnvProxy_1.shouldUseEnvProxy)()) {
        dispatcher = new undici_1.EnvHttpProxyAgent();
    }
    await Promise.all(results.map(async ({ screenshot, screenshot_id }) => {
        if (!screenshot) {
            return;
        }
        const url = new URL(screenshotsURL.href);
        url.searchParams.set('screenshot_id', screenshot_id);
        const { ok } = await (0, undici_1.fetch)(url, {
            method: 'POST',
            redirect: 'follow',
            dispatcher,
            headers: {
                'Content-Type': 'image/png',
                'X-API-Key': api_key
            },
            body: screenshot
        });
        if (!ok) {
            console.warn('@axe-core/watcher: Unable to send screenshot to server');
        }
    })).catch(requestErrorHandler);
};
exports.sendResultsToServer = sendResultsToServer;
class MaximumRetriesReached extends Error {
    constructor() {
        super('Maximum retries reached');
        this.name = 'MaximumRetriesReached';
    }
}
exports.MaximumRetriesReached = MaximumRetriesReached;
exports.default = exports.sendResultsToServer;
//# sourceMappingURL=sendResultsToServer.js.map