import { EventEmitter } from 'events';
import React from 'react';
import getWindow from 'get-window';
import { getLatestFiber, parseReactDomNodeDeep } from '../utils/dom-utils';
const findClosest = (from, isPass
// eslint-disable-next-line consistent-return
) => {
    let t = from;
    while (t) {
        if (isPass(t)) {
            return t;
        }
        t = t.parentElement;
    }
};
const findClosestFiber = (from, isPass
// eslint-disable-next-line consistent-return
) => {
    let t = from;
    while (t) {
        const res = isPass(t);
        if (res === true) {
            return t;
        }
        if (res) {
            t = res;
        }
        t = t.return;
    }
};
export class MometaDomApi extends EventEmitter {
    constructor(dom) {
        super();
        this.dom = dom;
        this.selectedKey = null;
        this._preventDefault = (evt) => {
            // React SyntheticEvent
            // if (evt.nativeEvent) {
            //   return
            // }
            const closestPass = findClosest(evt.target, (x) => x.__mometa && !x.__mometa.preventEvent);
            if (closestPass) {
                closestPass.__mometa.emit(evt.type, evt);
            }
            evt.stopPropagation();
            evt.preventDefault();
        };
        this.preventEvent = true;
    }
    preventDefaultPop(event, options) {
        this.dom.addEventListener(event, this._preventDefault, options);
        return () => {
            this.dom.removeEventListener(event, this._preventDefault, options);
        };
    }
    getMometaList() {
        const parents = new Set();
        const data = parseReactDomNodeDeep(this.dom);
        if (data === null || data === void 0 ? void 0 : data.fiber) {
            findClosestFiber(data.fiber, (f) => {
                var _a, _b;
                f = getLatestFiber(f);
                while (f && !((_a = f._debugSource) === null || _a === void 0 ? void 0 : _a.__mometa)) {
                    f = getLatestFiber(f.return);
                }
                let t = f;
                while (t && !(t.stateNode instanceof getWindow(this.dom).HTMLElement)) {
                    t = t.child;
                }
                if (t) {
                    // if (t.stateNode !== this.dom) {
                    //   return true
                    // }
                    parents.add((_b = getLatestFiber(f)._debugSource) === null || _b === void 0 ? void 0 : _b.__mometa);
                }
                return f;
            });
        }
        return Array.from(parents.values());
    }
    getMometaData() {
        var _a;
        const list = this.getMometaList();
        return (_a = list.find((x) => x.hash === this.selectedKey)) !== null && _a !== void 0 ? _a : list[0];
    }
    getKey() {
        var _a;
        return (_a = this.getMometaData()) === null || _a === void 0 ? void 0 : _a.hash;
    }
    findParents() {
        const parents = [];
        const data = parseReactDomNodeDeep(this.dom);
        if (data === null || data === void 0 ? void 0 : data.fiber) {
            findClosestFiber(data.fiber, (f) => {
                var _a, _b;
                f = getLatestFiber(f);
                while (f && !((_a = f._debugSource) === null || _a === void 0 ? void 0 : _a.__mometa)) {
                    f = getLatestFiber(f.return);
                }
                let t = f;
                while (t && !(t.stateNode instanceof getWindow(this.dom).HTMLElement)) {
                    t = t.child;
                }
                if (t) {
                    parents.push({
                        dom: t.stateNode,
                        mometa: (_b = getLatestFiber(f)._debugSource) === null || _b === void 0 ? void 0 : _b.__mometa
                    });
                }
                return f;
            });
        }
        return parents;
    }
}
/**
 * 为了不修改原有 dom 事件，使用自定义的发布订阅模拟实现 dom 事件
 * @param dom
 * @param events
 */
export function useProxyEvents(dom, events) {
    React.useEffect(() => {
        if (!events) {
            return () => { };
        }
        const disposes = [];
        for (const [name, fn] of Object.entries(events)) {
            let tName = name.toLowerCase();
            tName = tName.replace(/^on/, '').replace(/capture$/, '');
            dom.__mometa.addListener(tName, fn);
            disposes.push(() => {
                var _a;
                (_a = dom.__mometa) === null || _a === void 0 ? void 0 : _a.removeListener(tName, fn);
            });
        }
        return () => {
            disposes.forEach((fn) => fn());
        };
    }, [dom, events]);
}
//# sourceMappingURL=dom-api.js.map