"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IFRAME_SPATIAL_REFRESH_ACTION = exports.IFRAME_SPATIAL_RESPONSE_ACTION = exports.IFRAME_SPATIAL_REQUEST_ACTION = exports.IFRAME_MESSAGING_PARENT_REQUEST_ACTION = exports.IFRAME_MESSAGING_ACTION = void 0;
exports.createFrameMessageListener = createFrameMessageListener;
exports.createParentFrameMessageListener = createParentFrameMessageListener;
exports.requestIframeInfoFromParent = requestIframeInfoFromParent;
exports.createFrameSpatialListener = createFrameSpatialListener;
exports.createScrollSpatialRefreshListener = createScrollSpatialRefreshListener;
exports.requestFrameSpatialFromParent = requestFrameSpatialFromParent;
exports.getFrameSpatial = getFrameSpatial;
exports.refreshFrameSpatial = refreshFrameSpatial;
exports.getIframeElementInfo = getIframeElementInfo;
exports.ensureContentIsTracked = ensureContentIsTracked;
const dom_util_1 = require("@mablhq-internal/mablscript-find/dom-util");
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const shadowDomUtils_1 = require("./shadowDomUtils");
const messages_1 = require("./messages");
const domUtils_1 = require("./domUtils");
const customTestIdAttributesProvider_1 = require("./customTestIdAttributesProvider");
exports.IFRAME_MESSAGING_ACTION = 'mabl-frame-info';
exports.IFRAME_MESSAGING_PARENT_REQUEST_ACTION = 'mabl-frame-update-children';
exports.IFRAME_SPATIAL_REQUEST_ACTION = 'mabl-frame-spatial-request';
exports.IFRAME_SPATIAL_RESPONSE_ACTION = 'mabl-frame-spatial-response';
exports.IFRAME_SPATIAL_REFRESH_ACTION = 'mabl-frame-spatial-refresh';
const MAX_TRACK_ATTEMPTS = 10;
function getAllFrameElements() {
    const contexts = [
        document,
        ...(0, mablscriptFind_1.getChildrenShadowRoots)(document),
    ];
    const iframes = contexts.flatMap((context) => Array.from(('shadowRoot' in context && context.shadowRoot
        ? context.shadowRoot
        : context).querySelectorAll('iframe')));
    const frames = contexts.flatMap((context) => Array.from(('shadowRoot' in context && context.shadowRoot
        ? context.shadowRoot
        : context).querySelectorAll('frame')));
    return [...iframes, ...frames];
}
let trackedFrameSelector;
let isTracked = false;
function isContentTracked() {
    return isTracked;
}
function createFrameMessageListener() {
    window.addEventListener('message', (message) => {
        if (message.data && message.data.action === exports.IFRAME_MESSAGING_ACTION) {
            message.stopImmediatePropagation();
            sendTrackingInfoToBackground(message.data.frameInfo);
            isTracked = true;
        }
    }, true);
}
function createParentFrameMessageListener() {
    window.addEventListener('message', parentFrameMessageListener, true);
}
function parentFrameMessageListener(message) {
    if (message.data &&
        message.data.action === exports.IFRAME_MESSAGING_PARENT_REQUEST_ACTION) {
        message.stopImmediatePropagation();
        sendIframeInfoToAllChildren();
    }
    if (message.data && message.data.action === exports.IFRAME_SPATIAL_REQUEST_ACTION) {
        message.stopImmediatePropagation();
        handleSpatialRequestFromChild(message);
    }
}
function sendIframeInfoToAllChildren() {
    getAllFrameElements().forEach((frameElement) => {
        if (domUtils_1.MABL_INSERTED_ELEMENTS.includes(frameElement.id)) {
            return;
        }
        const xPath = (0, dom_util_1.createXPathFromElement)(frameElement);
        const frameInfo = (0, shadowDomUtils_1.createBaseEventMessageWithShadowParentsFromElement)(frameElement, 'record', 'switch-context-to', xPath, 0, (0, customTestIdAttributesProvider_1.getCustomTestIdAttributes)());
        frameElement.contentWindow?.postMessage({
            action: exports.IFRAME_MESSAGING_ACTION,
            frameInfo,
        }, '*');
    });
}
function requestIframeInfoFromParent() {
    if (isObjectElement()) {
        return;
    }
    sendMessageToFrames({
        action: exports.IFRAME_MESSAGING_PARENT_REQUEST_ACTION,
    });
}
function sendMessageToFrames(message) {
    window.parent.postMessage(message, '*');
}
function handleSpatialRequestFromChild(message) {
    const source = message.source;
    const accumulatedOffset = message.data.accumulatedOffset;
    const iframeElement = findIframeByContentWindow(source);
    if (!iframeElement) {
        return;
    }
    const rect = iframeElement.getBoundingClientRect();
    const newAccumulatedOffset = {
        x: accumulatedOffset.x + rect.left,
        y: accumulatedOffset.y + rect.top,
    };
    if (window === window.top) {
        const pageSize = {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
        };
        sendSpatialResponseToAllChildren({ x: 0, y: 0 }, pageSize);
    }
    else {
        window.parent.postMessage({
            action: exports.IFRAME_SPATIAL_REQUEST_ACTION,
            accumulatedOffset: newAccumulatedOffset,
        }, '*');
        const responseHandler = (responseMessage) => {
            if (responseMessage.data &&
                responseMessage.data.action === exports.IFRAME_SPATIAL_RESPONSE_ACTION) {
                window.removeEventListener('message', responseHandler, true);
                const myPosition = responseMessage.data.position ?? { x: 0, y: 0 };
                sendSpatialResponseToAllChildren(myPosition, responseMessage.data.pageSize);
            }
        };
        window.addEventListener('message', responseHandler, true);
    }
}
function sendSpatialResponseToAllChildren(myPosition, pageSize) {
    getAllFrameElements().forEach((frameElement) => {
        if (domUtils_1.MABL_INSERTED_ELEMENTS.includes(frameElement.id)) {
            return;
        }
        const frameRect = frameElement.getBoundingClientRect();
        const framePosition = {
            x: myPosition.x + frameRect.left,
            y: myPosition.y + frameRect.top,
        };
        frameElement.contentWindow?.postMessage({
            action: exports.IFRAME_SPATIAL_RESPONSE_ACTION,
            position: framePosition,
            pageSize,
        }, '*');
    });
}
function findIframeByContentWindow(contentWindow) {
    return getAllFrameElements().find((frame) => frame.contentWindow === contentWindow);
}
function createFrameSpatialListener() {
    window.addEventListener('message', (message) => {
        if (message.data &&
            message.data.action === exports.IFRAME_SPATIAL_RESPONSE_ACTION) {
            window.mablFrameInfo.position = message.data.position;
            window.mablFrameInfo.pageSize = message.data.pageSize;
        }
        if (message.data &&
            message.data.action === exports.IFRAME_SPATIAL_REFRESH_ACTION) {
            requestFrameSpatialFromParent();
            notifyChildFramesToRefreshSpatial();
        }
    }, true);
}
function notifyChildFramesToRefreshSpatial() {
    getAllFrameElements().forEach((frameElement) => {
        if (domUtils_1.MABL_INSERTED_ELEMENTS.includes(frameElement.id)) {
            return;
        }
        frameElement.contentWindow?.postMessage({
            action: exports.IFRAME_SPATIAL_REFRESH_ACTION,
        }, '*');
    });
}
function createScrollSpatialRefreshListener() {
    let scrollTimeout;
    window.addEventListener('scroll', () => {
        if (scrollTimeout) {
            global.clearTimeout(scrollTimeout);
        }
        scrollTimeout = global.setTimeout(() => {
            notifyChildFramesToRefreshSpatial();
        }, 50);
    }, true);
}
function requestFrameSpatialFromParent() {
    if (window === window.top) {
        window.mablFrameInfo.position = { x: 0, y: 0 };
        window.mablFrameInfo.pageSize = {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
        };
        return;
    }
    if (isObjectElement()) {
        return;
    }
    window.parent.postMessage({
        action: exports.IFRAME_SPATIAL_REQUEST_ACTION,
        accumulatedOffset: { x: 0, y: 0 },
    }, '*');
}
function getFrameSpatial() {
    return {
        position: window.mablFrameInfo.position,
        pageSize: window.mablFrameInfo.pageSize,
    };
}
async function refreshFrameSpatial() {
    const startTime = Date.now();
    if (window === window.top) {
        window.mablFrameInfo.position = { x: 0, y: 0 };
        window.mablFrameInfo.pageSize = {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight,
        };
        return getFrameSpatial();
    }
    return new Promise((resolve) => {
        const responseHandler = (message) => {
            if (message.data &&
                message.data.action === exports.IFRAME_SPATIAL_RESPONSE_ACTION) {
                window.removeEventListener('message', responseHandler, true);
                window.mablFrameInfo.position = message.data.position;
                window.mablFrameInfo.pageSize = message.data.pageSize;
                const endTime = Date.now();
                console.log('spatial response time', endTime - startTime);
                resolve(getFrameSpatial());
            }
        };
        window.addEventListener('message', responseHandler, true);
        requestFrameSpatialFromParent();
        global.setTimeout(() => {
            window.removeEventListener('message', responseHandler, true);
            resolve(getFrameSpatial());
        }, 1000);
    });
}
function sendTrackingInfoToBackground(frameSelector) {
    if (trackedFrameSelector) {
        return;
    }
    trackedFrameSelector = frameSelector;
    void window.__mabl.bridge.sendToMain({
        action: messages_1.IFRAME_REQUESTING_TRACKING,
        frameInfo: window.mablFrameInfo,
        frameElementInfo: {
            frameSelector,
            childFrames: [],
        },
    });
}
function getIframeElementInfo() {
    let frameInfo;
    if (window.frameElement) {
        frameInfo = window.frameElement;
    }
    else {
        frameInfo = document.createElement('iframe');
        frameInfo.name = window.name;
        frameInfo.src = window.location.href;
    }
    return {
        frameSelector: (0, dom_util_1.createBaseEventMessage)(frameInfo, 'record', 'switch-context-to', ''),
        childFrames: (0, domUtils_1.getIframesInfo)(),
    };
}
function isObjectElement() {
    const frameElement = window.frameElement;
    if (frameElement?.tagName.toLowerCase() === 'object') {
        return frameElement;
    }
    return undefined;
}
function sendMessageFromObjectElementContext(frameElement) {
    const xPath = (0, dom_util_1.createXPathFromElement)(frameElement);
    const contextInfo = (0, dom_util_1.createBaseEventMessage)(frameElement, 'record', 'switch-context-to', xPath);
    sendTrackingInfoToBackground(contextInfo);
    isTracked = true;
}
async function ensureContentIsTracked() {
    let attempts = 0;
    while (!isContentTracked() && attempts < MAX_TRACK_ATTEMPTS) {
        const frameElement = isObjectElement();
        if (frameElement) {
            sendMessageFromObjectElementContext(frameElement);
        }
        else {
            requestIframeInfoFromParent();
        }
        await new Promise((resolve) => window.setTimeout(resolve, 1000));
        attempts += 1;
    }
}
