import { ProxyEventListener }from './proxyEventListener';
import { proxyDocument }from './proxyDocument';
import { proxyHistory }from './proxyHistory';
import { proxyLocation }from './proxyLocation';
import { proxyLocalStorage, proxySessionStorage }from './proxyStorage';
import { MustardName, MustardURL } from '../typings';
import { EventCenterMicroApp } from '../communication';

export class SandBox {
    active = false; // 沙箱是否在运行
    microWindow = {}; // 代理的对象
    injectedKeys = new Set<string | symbol>(); // 新添加的属性，在卸载时清空

    name:MustardName; // 沙箱标识同app标识一致
    proxyEventListener:ProxyEventListener; // 全局事件代理
    proxyWindow; // window 代理
    proxyDocument; // document 代理
    proxyHistory; // history 代理
    proxyLocation; // location 代理
    proxyLocalStorage; // localStorage 代理
    proxySessionStorage; // sessionStorage 代理

    microApp: EventCenterMicroApp; // 事件通讯
  
    // todo
    // url: MustardURL
    constructor (name:MustardName, url: MustardURL) {
        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}'),
            )
        `;
    }
}