type IEventLisParameters$1 = Parameters<typeof addEventListener>;

type IType$1 = IEventLisParameters$1[0];
type Ilistener$1 = IEventLisParameters$1[1];
type Ioptions$1 = IEventLisParameters$1[2];

declare class ProxyEventListener$1 {
    eventLis = new Map<IType, Map<Ilistener, Ioptions>>();

    // 添加事件
    addEventListener (type: IType$1, listener: Ilistener$1, options: Ioptions$1) {
        if(!this.eventLis.has(type)) {
            this.eventLis.set(type, new Map());
        }
        const listeners = this.eventLis.get(type);
        listeners?.set(listener, options);
        return window.addEventListener(type, listener, options);
    }

    // 删除事件
    removeEventListener (type: IType$1, listener: Ilistener$1, options: Ioptions$1) {
        if(!this.eventLis.has(type)) {
            this.eventLis.set(type, new Map());
        }
        const listeners = this.eventLis.get(type);
        if(listeners?.get(listener) === options) {
            listeners?.delete(listener);
        }
        return window.removeEventListener(type, listener, options);
    }

    // 全部清除事件
    clear () {
        Array.from(this.eventLis.keys()).forEach(key => {
            const listeners = this.eventLis.get(key);
            if(listeners instanceof Map) {
                Array.from(listeners.keys()).forEach(listener => {
                    window.removeEventListener(key, listener, listeners.get(listener));
                });
            }
        });
    }
}

/* eslint-disable no-use-before-define */


interface MustardStateOptions$1 {
    origin?:MustardURL$1, // document 来源
    flushed?:boolean // 是否更新文档
}

interface MustardState$1 extends MustardStateOptions$1{
    data?: unknown, // pushState 和 replaceState 第一个参数
    index: number, // 用于计算当前state 的顺序
}

// 用于区分子应用
type BindMethod$1 = string;

type TCallback$1 = (value: unknown, oldValue:unknown, source:MustardName$1) => void;

// 子应用通讯类（注入到子应用的window.microApp）
declare class EventCenterMicroApp$1 {
    name:MustardName$1;

    constructor (name:MustardName$1) {
        this.name = name;
    }
    
    // 添加data事件监听
    addDataListener (fn:TCallback$1) {
        eventCenter.on(getEventDataKey(this.name), fn, { immediately: true, repeatSend: true });
    }

    // 解除data监听
    removeDataListener (fn:TCallback$1) {
        fn && eventCenter.off(getEventDataKey(this.name), fn);
    }
    
    // 解除所以的data监听事件
    clearDateListener () {
        eventCenter.off(getEventDataKey(this.name));
    }

    /**
     * 发送data数据修改事件
     * @param data 发送数据
     */
    dispatch (data:unknown) {
        globalDataChangeDispatch(this.name, data);
        eventCenter.dispatch(getEventDataChangeKey(this.name), this.name, data);
    }

    /**
     * 发送自定义事件
     * @param method 
     */
    dispatchCustomize (method:BindMethod$1, data:unknown) {
        eventCenter.dispatch(getEventBindKey(this.name, method), this.name, data);
    }
}

// 子应用生命周期通讯类（内部调用）
declare class EventCenterMicorLife$1 {
    private name:MustardName$1;

    constructor (name:MustardName$1) {
        this.name = name;
    }
    
    /**
     * 发送生命周期
     * @param state 子应用的生命周期
     */
    public dispatchLife (state:IAppStatus$1) {
        globalLifeDispatch(IAppStatus[state] as IAppStatusCN, this.name);
        eventCenter.dispatch(getEventLifeKeyByValue(this.name, state), this.name);
    }
}

declare class SandBox$1 {
    active = false; // 沙箱是否在运行
    microWindow = {}; // 代理的对象
    injectedKeys = new Set<string | symbol>(); // 新添加的属性，在卸载时清空

    name:MustardName$1; // 沙箱标识同app标识一致
    proxyEventListener:ProxyEventListener$1; // 全局事件代理
    proxyWindow; // window 代理
    proxyDocument; // document 代理
    proxyHistory; // history 代理
    proxyLocation; // location 代理
    proxyLocalStorage; // localStorage 代理
    proxySessionStorage; // sessionStorage 代理

    microApp: EventCenterMicroApp$1; // 事件通讯
  
    // todo
    // url: MustardURL
    constructor (name:MustardName$1, url: MustardURL$1) {
        this.name = name;
        this.proxyLocation = proxyLocation(this.name, url);
        this.proxyHistory = proxyHistory(this.name);
        this.proxyLocalStorage = proxyLocalStorage(this.name);
        this.proxySessionStorage = proxySessionStorage(this.name);
        this.proxyDocument = proxyDocument(this.name);
        this.proxyEventListener = new ProxyEventListener();
        this.microApp = new EventCenterMicroApp(this.name);
        this.proxyWindow = new Proxy(this.microWindow, {
            // 取值
            get: (target, key) => {
                // 优先从代理对象上取值
                if (Reflect.has(target, key)) {
                    return Reflect.get(target, key);
                }
                if(key === 'document') {
                    return this.proxyDocument;
                }
                if(key === 'addEventListener') {
                    return this.proxyEventListener.addEventListener.bind(this.proxyEventListener);
                }
                if(key === 'history') {
                    return this.proxyHistory;
                }
                if(key === 'location') {
                    return this.proxyLocation;
                }
                if(key === 'localStorage') {
                    return this.proxyLocalStorage;
                }
                if(key === 'sessionStorage') {
                    return this.proxySessionStorage;
                }

                if(key === 'microApp') {
                    return this.microApp;
                }
                    
                // 否则兜底到window对象上取值
                const rawValue = Reflect.get(window, key);
        
                // 如果兜底的值为函数，则需要绑定window对象，如：console、alert等
                if (typeof rawValue === 'function') {
                    const valueStr = rawValue.toString();
                    // 排除构造函数
                    if (!/^function\s+[A-Z]/.test(valueStr) && !/^class\s+/.test(valueStr)) {
                        return rawValue.bind(window);
                    }
                }
        
                // 其它情况直接返回
                return rawValue;
            },
            // 设置变量
            set: (target, key, value) => {
                // 沙箱只有在运行时可以设置变量
                if (this.active) {
                    Reflect.set(target, key, value);
                    // 记录添加的变量，用于后续清空操作
                    this.injectedKeys.add(key);
                }
                return true;
            },
            deleteProperty: (target, key) => {
                // 当前key存在于代理对象上时才满足删除条件
                if (Object.prototype.hasOwnProperty.call(target, key)) {
                    return Reflect.deleteProperty(target, key);
                }
                return true;
            },
            has (target, key) {
                return key in target || key in window;
            }
        });
    }

    start () {
        if(!this.active) {
            this.active = true;
        }
    }

    stop () {
        if(this.active) {
            this.microApp.clearDateListener();
            this.active = false;
            Array.from(this.injectedKeys.keys()).forEach(key => Reflect.deleteProperty(this.microWindow, key));
            this.injectedKeys.clear();
            this.proxyEventListener.clear();
        }
    }

    // 修改js作用域
    bindScope (code) {
        return `
            ;(function(window, self){
                const microApp = window.microApp;
                const history = window.history;
                const location = window.location;
                const document = window.document;
                const localStorage = window.localStorage;
                const sessionStorage = window.sessionStorage;
                const addEventListener = window.addEventListener;
                ${code}\n;
            }).call(
                mustardAppInfos.getAppProxyWindow('${this.name}'),
                mustardAppInfos.getAppProxyWindow('${this.name}'),
                mustardAppInfos.getAppProxyWindow('${this.name}'),
            )
        `;
    }
}

declare const rawAddEventListener$1 = HTMLElement.prototype.addEventListener;

type AddEventListenerParams$1 = Parameters<typeof rawAddEventListener$1>
type EventListenerType$1 = 'dataChange' | IAppStatusCN$1 | keyof HTMLElementEventMap;
type EventListenerListener$1 = AddEventListenerParams$1[1];
type EventListenerOptions$1 = AddEventListenerParams$1[2];

declare class MustardApp$1 extends HTMLElement {
    url:MustardURL$1 = ''; // 子应用资源地址
    name:MustardName$1 = ''; // 子应用标识
    // keepAlive:boolean = true; // dom移除是否保活

    checkUrlStop:()=>void; // URL 校验关闭

    static get observedAttributes () {
        return ['name', 'url'];
    }

    constructor () {
        super();
    }

    // 组件刷新
    reload () {
        const app = getAppFromInstance(this.name);
        if(app) {
            app.reload();
        }
    }

    // 子应用添加至页面
    connectedCallback () {
        if(!appIsExist(this.name) && this.url) {
            nextTick(() => {
                new App({
                    url: this.url,
                    name: this.name,
                    container: this
                });
            });
        }
        // 开启URL校验
        this.checkUrlStop = addEventListenerUrl(()=>{
            checkUrl(this.name);
        });
    }

    // 子应用从页面中移除
    disconnectedCallback () {
        // 关闭URL校验
        this.checkUrlStop?.();
        // getAppFromInstance(this.name)?.unmount(true);
    }

    // 子应用移动至新页面。
    adoptedCallback () {}

    /**
     * 属性变化
     * @param name 属性名
     * @param oldValue 属性旧值
     * @param newValue 属性新值
     */
    attributeChangedCallback (name, oldValue, newValue) {
        if(!this.name && name === 'name') {
            if(newValue === MainMustardApp) {
                throw new Error('子应用标识非法');
            }
            if(appIsExist(name)) {
                throw new Error(`子应用标识已存在: ${name}`);
            }else{
                this.name = newValue;
            }
        }else if(!this.url && name === 'url') {
            this.url = newValue;
        }
    }

    setAttribute (key:string, value:unknown) {
        if (/^mustard-app/i.test(this.tagName) && key === 'data') {
            // 发送数据
            eventCenter.dispatch(this.name, value);
        } else {
            rawSetAttribute.call(this, key, value);
        }
    }

    addEventListener (type: EventListenerType$1, listener: EventListenerListener$1, options?: EventListenerOptions$1): void {
        if(isFunction(listener)) {
            if(type === 'dataChange') {
                eventCenter.onData(this.name, listener);
            }else if(isIAppStatusKey(type)) {
                eventCenter.onLife(this.name, type, listener);
            }else{
                rawAddEventListener.call(this, type, listener, options);
            }
        }
    }

    removeEventListener (type: EventListenerType$1, listener: EventListenerListener$1, options?: EventListenerOptions$1): void {
        if(isFunction(listener)) {
            if(type === 'dataChange') {
                eventCenter.offData(this.name, listener);
            }else if(isIAppStatusKey(type)) {
                eventCenter.offLife(this.name, type, listener);
            }else{
                rawRemoveEventListener.call(this, type, listener, options);
            }
        }
    }
}

declare class App$1 {
    baseUrl: MustardURL$1;
    url: MustardURL$1;
    name: MustardName$1;
    container: MustardApp$1;

    sandbox: SandBox$1;

    loadCount: number = 0;
    status = IAppStatus$1.create;

    state: MustardState$1; // document 来源
    microLifeCenter: EventCenterMicorLife$1; // 生命周期通讯

    // 存放动态资源
    source = {
        links: new Map<string, SpurceValue>(), // 存放links
        scripts: new Map<string, SpurceValue>(), // 存放scripts
        domClick: '\n;' // 存放 dom attrs 上的事件
    };

    constructor ({ name, url: baseUrl, container }: IAppConstructor$1) {
        this.name = name;
        this.baseUrl = baseUrl;
        this.container = container;
        this.microLifeCenter = new EventCenterMicorLife(this.name);
        this.init();
    }

    // 刷新 卸载->初始化
    reload () {
        this.unmount(true);
        this.init();
    }

    // 初始化
    init () {
        this.status = IAppStatus.create;
        this.microLifeCenter.dispatchLife(this.status);
        // 初始化立刻存入 mustardAppInfos.appInstanceMap
        addInstance(this.name, this); 

        this.loadCount = 0;
        // 设置资源的真正地址
        this.url = getURL(this.name, this.baseUrl).href;
        
        this.source = {
            links: new Map<string, SpurceValue>(), // 存放links
            scripts: new Map<string, SpurceValue>(), // 存放scripts
            domClick: '\n;' // 存放 dom attrs 上的事件
        };

        // 刷新页面时，为了保证 document.origin 正确，默认取history
        this.state = decodeState(this.name);

        if(!this.state) {
            initState(this.name, '', '', this.url);
            this.state = decodeState(this.name);
        }
        
        this.status = IAppStatus.loading;
        this.microLifeCenter.dispatchLife(this.status);

        // 加载对应的资源
        loadHtml(this);
        // 初始化砂箱
        this.sandbox = new SandBox(this.name, this.url);
    }

    // 资源加载完时执行
    onLoad (htmlDom: HTMLElement) {
        this.loadCount += 1;
        // 第二次执行且组件未卸载时执行渲染
        if (this.loadCount === 2 && this.status !== IAppStatus.unmount) {
            // 执行mount方法
            this.mount(htmlDom);
        }
    }

    /**
     * 资源加载完成后进行渲染
     */
    mount (html: HTMLElement) {
        this.sandbox.start();
        // 克隆DOM节点
        const cloneHtml = html.cloneNode(true);
        // 创建一个fragment节点作为模版，这样不会产生冗余的元素
        const fragment = document.createDocumentFragment();
        Array.from(cloneHtml.childNodes).forEach((node) => {
            fragment.appendChild(node);
        });

        // 将格式化后的DOM结构插入到容器中
        this.container.appendChild(fragment);

        // 执行js
        let scripts = '';
        this.source.scripts.forEach((info) => {
            scripts += info.code + '\n;';
        });

        {
            (0, eval)(this.sandbox.bindScope(scripts + '\n;' + this.source.domClick));
        }

        // 标记应用为已渲染
        this.status = IAppStatus.mount;
        this.microLifeCenter.dispatchLife(this.status);
    }

    /**
     * 卸载应用
     * 执行关闭沙箱，清空缓存等操作
     * @param destory 是否销毁应用
     */
    unmount (destory: boolean) {
        this.sandbox.stop(); // 暂停沙箱
        this.status = IAppStatus.unmount;
        this.microLifeCenter.dispatchLife(this.status);
        if (destory) {
            this.destory();
        }
    }

    /**
     * 销毁应用
     */
    destory () {
        this.sandbox = null;
        this.container.innerHTML = '';
        this.status = IAppStatus.destory;
        this.microLifeCenter.dispatchLife(this.status);
        removeInstance(this.name);
    }

    /**
     * 子应用加载失败
     * @param error 失败原因
     */
    error (error: Error): void {
        errorLog(error);
        this.status = IAppStatus.error;
        this.microLifeCenter.dispatchLife(this.status);
        this.microLifeCenter = null;
    }
}

// location path 前缀

type IApp$1 = App$1; // 基座标识（禁用）

type MustardName$1 = string; // 子应用标识, 不能为 MainMustardApp

type MustardURL$1 = string; // `http://${string}`|`https://${string}`; // 应用开启地址

// 子应用状态
declare enum IAppStatus$1 {
    create = 0, // 初始化
    loading = 1, // 数据加载中
    mount = 2, // dom节点 挂载完成阶段
    unmount = 3, // dom节点 卸载
    destory = 4, // 销毁应用
    error = -100 // 子应用异常
}

type IAppStatusCN$1 = keyof typeof IAppStatus$1;

interface IAppConstructor$1 {
    name: MustardName$1;
    url: MustardURL$1; 
    container: MustardApp$1;
}       

declare global{
    interface HTMLElementTagNameMap{
        'mustard-app': MustardApp$1
    }
    interface Window{
        mustardAppInfos: { // 微应用实例
            currentReadDocMAppName?: MustardName$1;
            appInstanceMap: Map<MustardName$1, IApp$1>; // 当前所有子应用实例
            getAppProxyWindow: (appName: MustardName$1) => IApp$1['sandbox']['proxyWindow'];
        };
        // 子应用通讯方法
        microApp: EventCenterMicroApp$1
    }
}

type IEventLisParameters = Parameters<typeof addEventListener>;
type IType = IEventLisParameters[0];
type Ilistener = IEventLisParameters[1];
type Ioptions = IEventLisParameters[2];
declare class ProxyEventListener {
    eventLis: Map<string, Map<EventListenerOrEventListenerObject, boolean | AddEventListenerOptions>>;
    addEventListener(type: IType, listener: Ilistener, options: Ioptions): void;
    removeEventListener(type: IType, listener: Ilistener, options: Ioptions): void;
    clear(): void;
}

declare class SandBox {
    active: boolean;
    microWindow: {};
    injectedKeys: Set<string | symbol>;
    name: MustardName;
    proxyEventListener: ProxyEventListener;
    proxyWindow: any;
    proxyDocument: any;
    proxyHistory: any;
    proxyLocation: any;
    proxyLocalStorage: any;
    proxySessionStorage: any;
    microApp: EventCenterMicroApp;
    constructor(name: MustardName, url: MustardURL);
    start(): void;
    stop(): void;
    bindScope(code: any): string;
}

declare const rawAddEventListener: {
    <K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
    (type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
};
type AddEventListenerParams = Parameters<typeof rawAddEventListener>;
type EventListenerType = 'dataChange' | IAppStatusCN | keyof HTMLElementEventMap;
type EventListenerListener = AddEventListenerParams[1];
type EventListenerOptions = AddEventListenerParams[2];
declare class MustardApp extends HTMLElement {
    url: MustardURL;
    name: MustardName;
    checkUrlStop: () => void;
    static get observedAttributes(): string[];
    constructor();
    reload(): void;
    connectedCallback(): void;
    disconnectedCallback(): void;
    adoptedCallback(): void;
    /**
     * 属性变化
     * @param name 属性名
     * @param oldValue 属性旧值
     * @param newValue 属性新值
     */
    attributeChangedCallback(name: any, oldValue: any, newValue: any): void;
    setAttribute(key: string, value: unknown): void;
    addEventListener(type: EventListenerType, listener: EventListenerListener, options?: EventListenerOptions): void;
    removeEventListener(type: EventListenerType, listener: EventListenerListener, options?: EventListenerOptions): void;
}
declare function defineMustardAppElement(): void;

interface MustardStateOptions {
    origin?: MustardURL;
    flushed?: boolean;
}
interface MustardState extends MustardStateOptions {
    data?: unknown;
    index: number;
}

declare class App {
    baseUrl: MustardURL;
    url: MustardURL;
    name: MustardName;
    container: MustardApp;
    sandbox: SandBox;
    loadCount: number;
    status: IAppStatus;
    state: MustardState;
    microLifeCenter: EventCenterMicorLife;
    source: {
        links: Map<string, SpurceValue>;
        scripts: Map<string, SpurceValue>;
        domClick: string;
    };
    constructor({ name, url: baseUrl, container }: IAppConstructor);
    reload(): void;
    init(): void;
    onLoad(htmlDom: HTMLElement): void;
    /**
     * 资源加载完成后进行渲染
     */
    mount(html: HTMLElement): void;
    /**
     * 卸载应用
     * 执行关闭沙箱，清空缓存等操作
     * @param destory 是否销毁应用
     */
    unmount(destory: boolean): void;
    /**
     * 销毁应用
     */
    destory(): void;
    /**
     * 子应用加载失败
     * @param error 失败原因
     */
    error(error: Error): void;
}

type IApp = App;
type MustardName = string;
type MustardURL = string;
declare enum IAppStatus {
    create = 0,// 初始化
    loading = 1,// 数据加载中
    mount = 2,// dom节点 挂载完成阶段
    unmount = 3,// dom节点 卸载
    destory = 4,// 销毁应用
    error = -100
}
type IAppStatusCN = keyof typeof IAppStatus;
interface SpurceValue {
    code: string;
    isExternal?: boolean;
}
interface IAppConstructor {
    name: MustardName;
    url: MustardURL;
    container: MustardApp;
}
declare global {
    interface HTMLElementTagNameMap {
        'mustard-app': MustardApp;
    }
    interface Window {
        mustardAppInfos: {
            currentReadDocMAppName?: MustardName;
            appInstanceMap: Map<MustardName, IApp>;
            getAppProxyWindow: (appName: MustardName) => IApp['sandbox']['proxyWindow'];
        };
        microApp: EventCenterMicroApp;
    }
}

type BindMethod = string;
type TCallback = (value: unknown, oldValue: unknown, source: MustardName) => void;
type TLifeCallback = (key: MustardName) => void;
type TDataChangeCallback = (key: MustardName, data: unknown) => void;

declare function setGlobalEvents(options: Partial<Record<IAppStatusCN$1, TLifeCallback>> | Partial<Record<'dataChange', TDataChangeCallback>>): void;
declare class EventCenterMicroApp {
    name: MustardName$1;
    constructor(name: MustardName$1);
    addDataListener(fn: TCallback): void;
    removeDataListener(fn: TCallback): void;
    clearDateListener(): void;
    /**
     * 发送data数据修改事件
     * @param data 发送数据
     */
    dispatch(data: unknown): void;
    /**
     * 发送自定义事件
     * @param method
     */
    dispatchCustomize(method: BindMethod, data: unknown): void;
}
declare class EventCenterMicorLife {
    private name;
    constructor(name: MustardName$1);
    /**
     * 发送生命周期
     * @param state 子应用的生命周期
     */
    dispatchLife(state: IAppStatus$1): void;
}

export { MustardApp, defineMustardAppElement, setGlobalEvents };
