"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
    if (kind === "m") throw new TypeError("Private method is not writable");
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
    return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
    if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
    if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
    return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _Controller_takeScreenshots, _Controller_screenshots;
Object.defineProperty(exports, "__esModule", { value: true });
const readVariables_1 = __importDefault(require("./utils/readVariables"));
const sendResultsToServer_1 = __importDefault(require("./sendResultsToServer"));
const createDebugger_1 = __importDefault(require("./createDebugger"));
const assertVariablesWereWritten_1 = require("./utils/assertVariablesWereWritten");
const constants_1 = require("./utils/constants");
const testContext_1 = require("./utils/testContext");
class Controller {
    constructor({ debugLoggerName, integrationName, configurationFunction }) {
        this.testContext = null;
        _Controller_takeScreenshots.set(this, false);
        _Controller_screenshots.set(this, {});
        (0, assertVariablesWereWritten_1.assertVariablesWereWritten)(integrationName, configurationFunction);
        const variables = (0, readVariables_1.default)();
        this.axeCoreSettings = variables.axe_core_settings;
        this.runOptions = variables.run_options;
        this.isStopped = !variables?.auto_analyze;
        this.timeout = variables.timeout;
        this.debugLogger = (0, createDebugger_1.default)(debugLoggerName);
        __classPrivateFieldSet(this, _Controller_takeScreenshots, !!variables.take_screenshots, "f");
    }
    setTestContext(context) {
        this.testContext = (0, testContext_1.normalizeTestContext)(context);
    }
    async start({ timeout } = {}) {
        this.debugLogger(`Start: Invoked`);
        let timer = null;
        await Promise.race([
            this.executeScript(() => {
                return new Promise(resolve => {
                    if (!['http:', 'https:', 'file:'].includes(window.location.protocol)) {
                        resolve({ message: 'Clean skipped - invalid protocol' });
                    }
                    if (window.top !== window.self) {
                        resolve({
                            message: 'Clean skipped - Unable to analyze, not in top-level frame'
                        });
                    }
                    const fn = (event) => {
                        window.removeEventListener('axe:manual-mode-clean-done', fn);
                        resolve({ message: event.detail.message });
                    };
                    window.addEventListener('axe:manual-mode-clean-done', fn);
                    const event = new CustomEvent('axe:manual-mode-clean');
                    window.dispatchEvent(event);
                });
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher could not start automatic mode because \`start\` timed out. To resolve this problem, increase the \`timeout.start\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || this.timeout.start);
            })
        ])
            .then(result => {
            this.debugLogger(`Start: ${result.message}`);
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            this.isStopped = false;
        });
    }
    async stop({ timeout } = {}) {
        this.debugLogger(`Stop: Invoked (${this.isStopped ? 'not analyzing' : 'may analyze implicitly'})`);
        if (this.isStopped) {
            return Promise.resolve();
        }
        let timer = null;
        const screenshotId = __classPrivateFieldGet(this, _Controller_takeScreenshots, "f") ? crypto.randomUUID() : undefined;
        await Promise.race([
            this.executeScript(({ testContext, screenshot_id }) => {
                if (!['http:', 'https:', 'file:'].includes(window.location.protocol)) {
                    return Promise.resolve({ message: 'Skipped - Invalid protocol' });
                }
                if (window.top !== window.self) {
                    return Promise.resolve({
                        message: 'Skipped - Unable to analyze, not in top-level frame'
                    });
                }
                return new Promise(resolve => {
                    const fn = (event) => {
                        window.removeEventListener('axe:manual-mode-analyze-done', fn);
                        resolve(event.detail);
                    };
                    window.addEventListener('axe:manual-mode-analyze-done', fn);
                    const event = new CustomEvent('axe:manual-mode-analyze', {
                        detail: {
                            userRequestedAnalyze: false,
                            testContext,
                            screenshot_id
                        }
                    });
                    window.dispatchEvent(event);
                });
            }, {
                testContext: this.testContext ?? (0, testContext_1.getGlobalTestContext)(),
                screenshot_id: screenshotId
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher could not stop automatic mode because \`stop\` timed out. To resolve this problem, increase the \`timeout.stop\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || this.timeout.stop);
            })
        ])
            .then(async (result) => {
            this.debugLogger(`Stop: ${result.message}`);
            if (__classPrivateFieldGet(this, _Controller_takeScreenshots, "f") && result.hasViolations && screenshotId) {
                this.debugLogger('Stop: Capturing screenshot');
                try {
                    __classPrivateFieldGet(this, _Controller_screenshots, "f")[screenshotId] = await this.captureScreenshot();
                    this.debugLogger('Stop: Screenshot captured');
                }
                catch (error) {
                    this.debugLogger('Stop: Screenshot capture failed', { error });
                }
            }
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            this.isStopped = true;
        });
    }
    async analyze({ __Method, __UserRequestedAnalyze = true } = {}, { timeout } = {}) {
        this.debugLogger(`Analyze: Invoked${__Method ? ` - ${__Method}` : ''}`, {
            isStopped: this.isStopped,
            userRequestedAnalyze: __UserRequestedAnalyze
        });
        if (this.isStopped && !__UserRequestedAnalyze) {
            this.debugLogger('Analyze: Skipped', {
                isStopped: this.isStopped,
                userRequestedAnalyze: __UserRequestedAnalyze
            });
            return;
        }
        let timer = null;
        const screenshotId = __classPrivateFieldGet(this, _Controller_takeScreenshots, "f") ? crypto.randomUUID() : undefined;
        await Promise.race([
            this.executeScript(({ userRequestedAnalyze, isStopped, axeCoreSettings, runOptions, testContext, screenshot_id }) => {
                if (!['http:', 'https:', 'file:'].includes(window.location.protocol)) {
                    if (userRequestedAnalyze) {
                        return Promise.resolve({
                            message: `Cannot perform analysis - invalid protocol: ${window.location.protocol}`,
                            error: true
                        });
                    }
                    return Promise.resolve({ message: 'Skipped - Invalid protocol' });
                }
                if (window.top !== window.self) {
                    return Promise.resolve({
                        message: 'Skipped - Unable to analyze, not in top-level frame'
                    });
                }
                return new Promise(resolve => {
                    const fn = (event) => {
                        window.removeEventListener('axe:manual-mode-analyze-done', fn);
                        resolve(event.detail);
                    };
                    window.addEventListener('axe:manual-mode-analyze-done', fn);
                    const event = new CustomEvent('axe:manual-mode-analyze', {
                        detail: {
                            userRequestedAnalyze,
                            isStopped,
                            axeCoreSettings,
                            runOptions,
                            testContext,
                            screenshot_id
                        }
                    });
                    window.dispatchEvent(event);
                });
            }, {
                userRequestedAnalyze: __UserRequestedAnalyze,
                isStopped: this.isStopped,
                axeCoreSettings: this.axeCoreSettings,
                runOptions: this.runOptions,
                testContext: this.testContext ?? (0, testContext_1.getGlobalTestContext)(),
                screenshot_id: screenshotId
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher timed out before it could finish analyzing the page state. To resolve this problem, increase the \`timeout.analyze\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || this.timeout.analyze);
            })
        ])
            .then(async (result) => {
            this.debugLogger(`Analyze: ${result.message}`);
            if (result.error) {
                throw new Error(result.message);
            }
            if (__classPrivateFieldGet(this, _Controller_takeScreenshots, "f") && result.hasViolations && screenshotId) {
                this.debugLogger('Analyze: Capturing screenshot');
                try {
                    __classPrivateFieldGet(this, _Controller_screenshots, "f")[screenshotId] = await this.captureScreenshot();
                    this.debugLogger('Analyze: Screenshot captured');
                }
                catch (error) {
                    this.debugLogger('Analyze: Screenshot capture failed', { error });
                }
            }
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
        });
    }
    async flush({ timeout } = {}) {
        this.debugLogger(`Flush: Invoked (${this.isStopped ? 'auto-analysis stopped' : 'may analyze implicitly'})`);
        let timer = null;
        const screenshotId = __classPrivateFieldGet(this, _Controller_takeScreenshots, "f") ? crypto.randomUUID() : undefined;
        await Promise.race([
            this.executeScript(({ isStopped, axeCoreSettings, runOptions, testContext, screenshot_id }) => {
                if (!['http:', 'https:', 'file:'].includes(window.location.protocol)) {
                    return Promise.resolve([]);
                }
                if (window.top !== window.self) {
                    return Promise.resolve([]);
                }
                return new Promise(resolve => {
                    const receivedResults = [];
                    const onFlushEnd = () => {
                        window.removeEventListener('axe:flush-end', onFlushEnd);
                        window.removeEventListener('axe:result', onAxeResult);
                        resolve(receivedResults);
                    };
                    const onAxeResult = (e) => {
                        receivedResults.push(...e.detail);
                    };
                    window.addEventListener('axe:result', onAxeResult);
                    window.addEventListener('axe:flush-end', onFlushEnd);
                    const event = new CustomEvent('axe:flush-start', {
                        detail: {
                            isStopped,
                            axeCoreSettings,
                            runOptions,
                            testContext,
                            screenshot_id
                        }
                    });
                    window.dispatchEvent(event);
                });
            }, {
                isStopped: this.isStopped,
                axeCoreSettings: this.axeCoreSettings,
                runOptions: this.runOptions,
                testContext: this.testContext ?? (0, testContext_1.getGlobalTestContext)(),
                screenshot_id: screenshotId
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher timed out sending results to the server. To resolve this problem, increase the \`timeout.flush\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || this.timeout.flush);
            })
        ])
            .then(async (results) => {
            this.debugLogger(`Flush: Received ${results.length} results`);
            if (__classPrivateFieldGet(this, _Controller_takeScreenshots, "f")) {
                for (const result of results) {
                    const hasViolations = (result.results?.violations?.length ?? 0) > 0;
                    if (!hasViolations) {
                        continue;
                    }
                    if (result.screenshot_id &&
                        result.screenshot_id in __classPrivateFieldGet(this, _Controller_screenshots, "f")) {
                        result.screenshot = __classPrivateFieldGet(this, _Controller_screenshots, "f")[result.screenshot_id];
                    }
                    else if (result.screenshot_id === screenshotId) {
                        this.debugLogger('Flush: Capturing screenshot');
                        try {
                            result.screenshot = await this.captureScreenshot();
                            this.debugLogger('Flush: Screenshot captured');
                        }
                        catch (error) {
                            this.debugLogger('Flush: Screenshot capture failed', {
                                error
                            });
                            result.screenshot_id = null;
                        }
                    }
                    else {
                        result.screenshot_id = null;
                    }
                }
                __classPrivateFieldSet(this, _Controller_screenshots, {}, "f");
            }
            await (0, sendResultsToServer_1.default)({
                results,
                debugLogger: this.debugLogger
            });
            this.debugLogger('Flush: Complete');
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
        });
    }
}
_Controller_takeScreenshots = new WeakMap(), _Controller_screenshots = new WeakMap();
exports.default = Controller;
//# sourceMappingURL=Controller.js.map