"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliTrainingContext = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
const browserLauncher_1 = require("../../browserLauncher");
const AwaitTabStep_1 = __importDefault(require("../sharedUtils/mablscript/canonical/AwaitTabStep"));
const TrainingContextBase_1 = require("../background/TrainingContextBase");
const messages_1 = require("../sharedUtils/messages");
const EXPOSED_MESSAGING_FUNCTION = 'mablSendMessageToMain';
class CliTrainingContext extends TrainingContextBase_1.TrainingContextBase {
    constructor(options) {
        super({
            runInMainWorld: false,
            exposedMessagingFunction: EXPOSED_MESSAGING_FUNCTION,
            onInitializeFrame: async (frame, forceInjection) => {
                await this.safeInjectContentScript(frame, undefined, forceInjection);
            },
        });
        this.page = options.page;
        this.browser = options.browser;
        this.onNewTabDetected = options.onNewTabDetected;
        this.recordingEnabled = options.recordingEnabled ?? false;
        this.customTestIdAttributes = options.customTestIdAttributes ?? [];
        this.frameContextTracker.setCurrentPageId(options.page.getPageId());
        this.browser.on(browserLauncher_1.BrowserEvent.PageCreated, async (newPage) => {
            if (newPage !== this.page) {
                await this.handleNewPage(newPage);
            }
        });
    }
    async handleNewPage(page) {
        try {
            await this.setupContentBridge(page);
            await this.injectContentScriptToAllFrames(page);
            this.addTrainingTabAndRecordAwaitTabStep(page, false);
        }
        catch (e) {
            const message = e instanceof Error ? e.message : String(e);
            console.error(`[Frame tracking] Error handling new page: ${message.split('\n')[0]}`);
        }
    }
    getBrowser() {
        return Promise.resolve(this.browser);
    }
    getBrowserSync() {
        return this.browser;
    }
    getActivePage() {
        const currentPageId = this.frameContextTracker.getCurrentPageId();
        return Promise.resolve(this.frameContextTracker.getPage(currentPageId));
    }
    addTrainingTabAndRecordAwaitTabStep(page, skipRecordStep) {
        const pageId = page.mainFrame().id();
        this.frameContextTracker.trackFramePage(pageId);
        if (!skipRecordStep && this.onNewTabDetected) {
            const tabSelectorInfo = this.frameContextTracker.getPageSelectorInfo(pageId);
            if (tabSelectorInfo) {
                const awaitTabStep = new AwaitTabStep_1.default(tabSelectorInfo);
                this.onNewTabDetected(awaitTabStep);
            }
        }
    }
    isOpenEmail(_step) {
        return false;
    }
    async initialize() {
        await this.setupContentBridge();
        await this.injectContentScriptToAllFrames();
        const mainFrameId = this.page.mainFrame().id();
        this.frameContextTracker.setCurrentPageId(mainFrameId);
    }
    getPage() {
        return this.page;
    }
    async takeScreenshot() {
        const activePage = await this.getActivePage();
        if (!activePage) {
            console.error('No active page found to take screenshot');
            return undefined;
        }
        return activePage.screenshot();
    }
    getCurrentUrl() {
        return this.page.url();
    }
    async navigateTo(url) {
        await this.page.goto(url);
    }
    async setupContentBridge(page = this.page) {
        try {
            await page.exposeFunction(EXPOSED_MESSAGING_FUNCTION, this.handleMessageFromContent.bind(this));
        }
        catch (e) {
            console.debug('Content bridge setup note:', e);
        }
    }
    setMessageHandler(handler) {
        this.customMessageHandler = handler;
    }
    setRecordingEnabled(enabled) {
        this.recordingEnabled = enabled;
    }
    isRecordingEnabled() {
        return this.recordingEnabled;
    }
    handleMessageFromContent(message) {
        if (typeof message === 'string') {
            try {
                const payload = JSON.parse(message);
                if (payload.type === 'exposedFun') {
                    return this.handleMessageFromContent(payload.args[0]);
                }
            }
            catch {
                console.debug('Could not parse wrapped binding call:', message);
            }
        }
        const msg = message;
        console.debug('Content message received:', msg?.action);
        if (msg?.action === 'check-training-status') {
            const response = {
                trainerIsActive: true,
                trainingStatusForTab: true,
                recordingStateActive: this.recordingEnabled,
                captureHovers: false,
                replayRunning: false,
                trackIframes: true,
                customTestIdAttributes: this.customTestIdAttributes,
            };
            return response;
        }
        if (msg?.action === messages_1.IFRAME_REQUESTING_TRACKING) {
            const iframeMsg = msg;
            this.trackFrameInfo(iframeMsg.frameInfo.frameId, iframeMsg.frameElementInfo.frameSelector);
            return { acknowledged: true };
        }
        if (this.customMessageHandler) {
            return this.customMessageHandler(message);
        }
        return { acknowledged: true };
    }
    static loadContentScript() {
        if (!CliTrainingContext.contentScriptSource) {
            let contentJsPath;
            if (CliTrainingContext.loadFromSourceDir) {
                const buildDir = (0, path_1.resolve)(__dirname, '../..');
                if (buildDir.includes('mabl-cli-build')) {
                    const workspaceRoot = (0, path_1.resolve)(buildDir, '../..');
                    contentJsPath = (0, path_1.resolve)(workspaceRoot, 'runtime/src/resources/contentJs/content.js');
                    console.log(`[ContentJs] Loading from SOURCE: ${contentJsPath}`);
                }
                else {
                    contentJsPath = (0, path_1.resolve)(__dirname, '../../resources/contentJs/content.js');
                }
            }
            else {
                contentJsPath = (0, path_1.resolve)(__dirname, '../../resources/contentJs/content.js');
            }
            try {
                CliTrainingContext.contentScriptSource = (0, fs_1.readFileSync)(contentJsPath, 'utf-8');
            }
            catch (e) {
                console.warn('Could not load content.js from:', contentJsPath, e);
                CliTrainingContext.contentScriptSource = `
          // Minimal content script stub
          window.__mabl = window.__mabl || {};
          window.__mabl.messageListener = function(msg) {
            console.debug('Content message listener:', msg?.action);
            return { success: false, message: 'Content script not loaded' };
          };
          window.__mablInit = true;
        `;
            }
        }
        return CliTrainingContext.contentScriptSource;
    }
    static clearContentScriptCache() {
        CliTrainingContext.contentScriptSource = undefined;
        CliTrainingContext.loadFromSourceDir = true;
    }
    async reinjectContentScript() {
        CliTrainingContext.clearContentScriptCache();
        const frames = this.page.frames();
        const contentScript = CliTrainingContext.loadContentScript();
        console.log(`[ContentJs] Reinjecting content script to ${frames.length} frame(s)...`);
        let successCount = 0;
        for (const frame of frames) {
            try {
                await frame.evaluateCodeInSecondaryWorld(() => {
                    if (window.__mabl?.messageListener) {
                        try {
                            window.__mabl.messageListener({
                                action: 'STOP_LISTENERS',
                            });
                        }
                        catch (e) {
                        }
                    }
                });
                await frame.evaluateCodeInSecondaryWorld(() => {
                    window.__mablInit = false;
                    if (window.__mabl) {
                        window.__mabl = undefined;
                    }
                    console.log('%c[mabl] Content script reloading...', 'color: #ff6b6b; font-weight: bold;');
                });
                await frame.initializeExposedFunctionInSecondaryWorld(EXPOSED_MESSAGING_FUNCTION);
                await frame.evaluateCodeInSecondaryWorld(contentScript);
                await frame.evaluateCodeInSecondaryWorld(() => {
                    console.log('%c[mabl] ✓ Content script reloaded!', 'color: #51cf66; font-weight: bold;');
                });
                successCount++;
                console.log(`[ContentJs] ✓ Reinjected to frame: ${frame.url()}`);
            }
            catch (e) {
                console.debug(`[ContentJs] ✗ Could not reinject to frame: ${e}`);
            }
        }
        console.log(`[ContentJs] Reinjection complete: ${successCount}/${frames.length} frames`);
    }
    async injectContentScriptToAllFrames(page = this.page) {
        const frames = page.frames();
        const contentScript = CliTrainingContext.loadContentScript();
        for (const frame of frames) {
            await this.safeInjectContentScript(frame, contentScript);
        }
        page.on('frameattached', async (frame) => {
            await this.safeInjectContentScript(frame);
        });
        page.on('framenavigated', async (frame) => {
            await this.safeInjectContentScript(frame);
        });
    }
    async safeInjectContentScript(frame, contentScript, forceInjection = false) {
        try {
            await this.frameContextTracker.trackAndInjectContentJs(frame, contentScript ?? CliTrainingContext.loadContentScript(), forceInjection, false);
        }
        catch (error) {
            const message = error instanceof Error ? error.message : String(error);
            console.debug(`[Frame tracking] Could not inject to frame: ${message.split('\n')[0]}`);
        }
    }
}
exports.CliTrainingContext = CliTrainingContext;
CliTrainingContext.loadFromSourceDir = false;
