import { __read, __spreadArray } from "tslib";
/* eslint-disable @typescript-eslint/prefer-optional-chain */
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
import { applyRecord, hookMethodDangerously } from '@slardar/sdk-template';
import { now } from '../../utils';
var PAGE_ACTIVITY_DELAY = 100;
var MAX_PAGE_ACTIVITY_DELAY = 10000;
var ROOT_TAGS = ['BODY', 'HTML', 'HEAD'];
// TODO pengli 可以先独立hook, 然后再设计一个插件通信机制
/**
 * 劫持 XHR.send 方法，回调 uniqId 为偶数
 */
export var hookXHRSend = function (send, before, after) {
    var uniqId = 0;
    return function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var requestId = (uniqId += 2);
        before(requestId, now());
        hookMethodDangerously(this, 'onreadystatechange', function (origin) {
            return function () {
                var ev = [];
                for (var _i = 0; _i < arguments.length; _i++) {
                    ev[_i] = arguments[_i];
                }
                this.readyState === 4 && after(requestId);
                return origin && origin.apply(this, ev);
            };
        })();
        return send.apply(this, args);
    };
};
/**
 * 劫持 fetch，回调 uniqId 为奇数
 */
export var hookFetch = function (_fetch, before, after) {
    var uniqId = 1;
    return function () {
        var args = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            args[_i] = arguments[_i];
        }
        var fetchPromise = _fetch.apply(void 0, __spreadArray([], __read(args), false));
        var requestId = (uniqId += 2);
        before(requestId, now());
        var onResolve = function () {
            after(requestId);
        };
        var onReject = function () {
            after(requestId);
        };
        fetchPromise.then(onResolve, onReject);
        return fetchPromise;
    };
};
/**
 * 劫持 XHR 和 fetch，监听当前页面未完成的 请求数量
 */
export var applyIncompleteReq = function (global, XMLHttpRequest) {
    var _a = __read(applyRecord(), 3), incompleteReq = _a[0], before = _a[1], after = _a[2];
    XMLHttpRequest && hookMethodDangerously(XMLHttpRequest.prototype, 'send', hookXHRSend)(before, after);
    global && hookMethodDangerously(global, 'fetch', hookFetch)(before, after);
    return [incompleteReq];
};
/**
 * 控制等待策略和强制结算
 * 结算策略: 没有进行中的请求, 没有dom变更, 没有resource or longtask
 */
export var waitActionComplete = function (cb, forceClear, win) {
    var idleTimer;
    var maxIdleTimer;
    var notify = function () {
        win.clearTimeout(idleTimer);
        idleTimer = win.setTimeout(function () {
            cb();
        }, PAGE_ACTIVITY_DELAY);
    };
    var start = function () {
        win.clearTimeout(maxIdleTimer);
        maxIdleTimer = win.setTimeout(function () {
            cb();
            forceClear();
        }, MAX_PAGE_ACTIVITY_DELAY);
        notify();
    };
    var complete = function () {
        win.clearTimeout(idleTimer);
        win.clearTimeout(maxIdleTimer);
    };
    return [start, notify, complete];
};
/**
 * 从target中获取path
 */
export var getDomPath = function (element) {
    var el = element;
    var stack = [];
    try {
        while (el.parentNode !== null) {
            var sibCount = 0;
            var sibIndex = 0;
            // eslint-disable-next-line @typescript-eslint/prefer-for-of
            for (var i = 0; i < el.parentNode.childNodes.length; i++) {
                var sib = el.parentNode.childNodes[i];
                if (sib.nodeName === el.nodeName) {
                    if (sib === el) {
                        sibIndex = sibCount;
                    }
                    sibCount++;
                }
            }
            if (el.hasAttribute('id') && el.id !== '') {
                stack.unshift(el.nodeName + '#' + el.id);
            }
            else if (sibCount > 1) {
                stack.unshift(el.nodeName + ':eq(' + sibIndex + ')');
            }
            else {
                stack.unshift(el.nodeName);
            }
            el = el.parentNode;
        }
        // removes the html element
        return stack.slice(1).join('>');
    }
    catch (_a) {
        return;
    }
};
export var isSupportsElementClosest = (function () {
    var supportsElementClosest;
    return function () {
        return supportsElementClosest === undefined
            ? (supportsElementClosest = 'closest' in HTMLElement.prototype)
            : supportsElementClosest;
    };
})();
export var findElementWithAttributeByParents = function (target, attribute, maxParentLoops) {
    if (maxParentLoops === void 0) { maxParentLoops = 10; }
    var element = target;
    for (var i = 0; i < maxParentLoops && element; i++) {
        if (~ROOT_TAGS.indexOf(element.nodeName))
            return;
        if (element.hasAttribute(attribute)) {
            return element;
        }
        element = element.parentElement;
    }
};
export var getActionNameByAttribute = function (target, attribute) {
    var elementWithAttribute;
    if (isSupportsElementClosest()) {
        elementWithAttribute = target.closest("[" + attribute + "]");
    }
    else {
        elementWithAttribute = findElementWithAttributeByParents(target, attribute);
    }
    if (!elementWithAttribute)
        return;
    var name = elementWithAttribute.getAttribute(attribute);
    // Possibly length of name is too long to be stored on backend.Let it go for now.Add truncation if someone oncalled
    return name.trim();
};
export var getActionName = function (target, attribute) {
    return getActionNameByAttribute(target, attribute) || target.innerText;
};
//# sourceMappingURL=util.js.map