import { __assign, __awaiter, __generator, __read } from "tslib";
// Import Libs and Handlers
import * as React from 'react';
import { autorun, observable, reaction } from 'mobx';
import { get, isEqual } from 'lodash-es';
import { app, createPageApi } from '../app/global-api'; // 取对应子包app
import { AppRender } from '../handlers/RenderWrapper';
import { _WEDA_CLOUD_SDK as WEDA_CLOUD_SDK } from '@cloudbase/weda-client';
import { generateEmit } from '../utils';
import { bindFuncObj, checkAuth, createComputed, createWidgets, retryDataBinds, toCssText } from '../utils/index';
import { usePageLifeCycle } from '../utils/lifecycle';
import { useScrollTop } from '../utils/hooks';
import { processCommonStyle2CSSProperties } from '@cloudbase/cals';
import { runtime } from '../utils/adapter';
import { loadMicroApp } from 'qiankun';
import { InjectContext } from '../router';
var createDataset = WEDA_CLOUD_SDK.createDataset, createStateDataSourceVar = WEDA_CLOUD_SDK.createStateDataSourceVar, generateParamsParser = WEDA_CLOUD_SDK.generateParamsParser, EXTRA_API = WEDA_CLOUD_SDK.EXTRA_API;
// Init
// eslint-disable-next-line react/display-name
export default React.memo(App, function (pre, next) {
    var _a;
    var reuseWidget = (_a = next.options) === null || _a === void 0 ? void 0 : _a.reuseWidget;
    var deepEqualKey = reuseWidget ? 'page' : '';
    for (var key in next) {
        if (key !== deepEqualKey && next[key] !== pre[key]) {
            return false;
        }
    }
    if (next[deepEqualKey] && !isEqual(next[deepEqualKey], pre[deepEqualKey])) {
        return false;
    }
    return true;
});
function App(_a) {
    var page = _a.page, generateComponentsMap = _a.generateComponentsMap, generateActionsMap = _a.generateActionsMap, generateLowcodeModule = _a.generateLowcodeModule, generateWidgetsContext = _a.generateWidgetsContext, generateDataBinds = _a.generateDataBinds, generateComponentSchema = _a.generateComponentSchema, generateContext = _a.generateContext, onRender = _a.onRender, onMounted = _a.onMounted, _b = _a.injectContext, injectContext = _b === void 0 ? {} : _b, _c = _a.initDataContext, initDataContext = _c === void 0 ? {} : _c, _d = _a.options, options = _d === void 0 ? { reuseWidget: false, looseError: false } : _d;
    var _e = __read(React.useState(false), 2), pageContextInited = _e[0], setPageContextInited = _e[1];
    var _f = __read(React.useState(Date.now()), 2), _ = _f[0], setFourceUpdate = _f[1];
    // 数据容器的上下文数据
    var dataContextRef = React.useRef(observable((injectContext === null || injectContext === void 0 ? void 0 : injectContext.dataContext) || initDataContext));
    var dataContext = dataContextRef.current;
    var widgetsContextRef = React.useRef({});
    React.useEffect(function () {
        if (injectContext === null || injectContext === void 0 ? void 0 : injectContext.dataContext) {
            if (dataContextRef.current) {
                for (var key in dataContextRef.current) {
                    if (!injectContext.dataContext[key]) {
                        dataContextRef.current[key] = null;
                    }
                }
            }
            for (var key in injectContext.dataContext) {
                dataContextRef.current[key] = injectContext.dataContext[key];
            }
            console.log('<<<<<<<<<<<<<<<<<<<<<<<< dataContext change');
            setFourceUpdate(Date.now());
        }
    }, [injectContext === null || injectContext === void 0 ? void 0 : injectContext.dataContext]);
    // 兼容 this.state / $page.state 两种模式
    var pageCodeContextRef = React.useRef(createPageApi());
    var $page = pageCodeContextRef.current;
    var lowcode = generateLowcodeModule();
    React.useEffect(function () {
        if (!(injectContext === null || injectContext === void 0 ? void 0 : injectContext.$page)) {
            var dataset = createDataset(page.id);
            var state = observable(lowcode.state || {});
            state.dataset = dataset;
            Object.assign($page, {
                id: page.id,
                state: state,
                computed: createComputed(lowcode.computed || {}, pageCodeContextRef.current),
                handler: bindFuncObj(lowcode.handler || {}, pageCodeContextRef.current),
                randerer: lowcode.renderer,
                dataset: dataset,
            });
        }
        else {
            Object.assign($page, {
                id: page.id,
                state: injectContext.$page.state,
                computed: injectContext.$page.computed,
                handler: injectContext.$page.handler,
                randerer: injectContext.$page.randerer,
                dataset: injectContext.$page.dataset,
            });
        }
        setPageContextInited(true);
    }, []);
    var _g = React.useMemo(function () {
        if (pageContextInited) {
            var globalCtx = {
                $page: $page,
                app: app,
                $app: app,
                actionsMap: (generateActionsMap === null || generateActionsMap === void 0 ? void 0 : generateActionsMap()) || {},
            };
            var widgetsContext_1, databinds = void 0, componentSchema_1;
            if (generateContext) {
                var context = generateContext(globalCtx, page);
                widgetsContext_1 = context.widgetContext;
                databinds = context.dataBinds;
                componentSchema_1 = context.componentSchema;
            }
            else {
                widgetsContext_1 = generateWidgetsContext(page);
                databinds = generateDataBinds(globalCtx, page);
                componentSchema_1 = generateComponentSchema(globalCtx, page);
            }
            // widgets 内的 dataBinds 可能需要关联 widgets，需要重新执行 dataBinds
            $page._dataBinds = databinds;
            return { componentSchema: componentSchema_1, widgetsContext: widgetsContext_1 };
        }
    }, [pageContextInited, page]), componentSchema = _g.componentSchema, widgetsContext = _g.widgetsContext;
    React.useMemo(function () {
        if (pageContextInited) {
            var _a = createWidgets(options.reuseWidget
                ? {
                    widgets: widgetsContextRef.current.widgets,
                    widgetProps: widgetsContextRef.current.widgetProps,
                    nodeMap: widgetsContextRef.current.nodeMap,
                }
                : {}, widgetsContext, $page._dataBinds || {}, dataContext), widgets = _a.widgets, nodeMap = _a.nodeMap;
            $page.widgets = widgets;
            widgetsContextRef.current = { widgetProps: widgetsContext, nodeMap: nodeMap, widgets: widgets };
            retryDataBinds();
        }
    }, [widgetsContext, dataContext]);
    return (pageContextInited && (React.createElement(AppContent, { page: page, lowcode: lowcode, componentSchema: componentSchema, pageCodeContext: pageCodeContextRef.current, virtualFields: generateComponentsMap(), onMounted: onMounted, onRender: onRender, dataContext: dataContext, 
        /**
         * 更新数据容器的上下文的方法
         * 会传递到事件emit的地方，将从组件获取到的数据data赋值给上下文
         * 当组件卸载时，传过来的data为undefined即可
         * {
         *   id1: [{...}],
         *   id2: {...},
         *   id3: undefined,
         *   id4: null,
         *   ...
         * }
         * @param id
         * @param data
         */
        // updateContext={function (id, data) {
        //   if (id && !injectContext?.dataContext) {
        //     dataContext[id] = { data };
        //   }
        //   injectContext?.onDataContextChange?.(id, data);
        // }}
        options: options })));
}
function AppContent(_a) {
    var _this = this;
    var _b, _c, _d, _e, _f;
    var page = _a.page, lowcode = _a.lowcode, componentSchema = _a.componentSchema, pageCodeContext = _a.pageCodeContext, virtualFields = _a.virtualFields, _g = _a.onMounted, onMounted = _g === void 0 ? function (props) {
        var _a;
        // eslint-disable-next-line react/prop-types
        (_a = props === null || props === void 0 ? void 0 : props.default) === null || _a === void 0 ? void 0 : _a.call(props);
    } : _g, _h = _a.onRender, onRender = _h === void 0 ? function () { } : _h, dataContext = _a.dataContext, updateContext = _a.updateContext, options = _a.options;
    // 检查权限
    var _j = __read(React.useState(false), 2), weDaHasLogin = _j[0], setWeDaHasLogin = _j[1];
    var containerRef = React.useRef(null);
    var microApp = React.useRef(null);
    var pureSrc = (_b = page.attributes) === null || _b === void 0 ? void 0 : _b.src;
    var isPure = !!pureSrc;
    var _k = React.useContext(InjectContext).checkPageAuth, checkPageAuth = _k === void 0 ? checkAuth : _k;
    // Web 环境页面级别生命周期
    usePageLifeCycle(__assign(__assign({}, lowcode === null || lowcode === void 0 ? void 0 : lowcode.lifecycle), { events: getPageEvents(componentSchema), 
        // eslint-disable-next-line @typescript-eslint/no-misused-promises
        beforePageCustomLaunch: function (query) { return __awaiter(_this, void 0, void 0, function () {
            var checkAuthResult;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        onMounted({
                            page: page,
                            default: function () {
                                var _a;
                                var document = (runtime === null || runtime === void 0 ? void 0 : runtime.document) || window.document;
                                document.title = ((_a = page.attributes) === null || _a === void 0 ? void 0 : _a.title) || page.id;
                            },
                        });
                        EXTRA_API.setParams(page.id, query || {});
                        initWatchMethods(pageCodeContext);
                        return [4 /*yield*/, checkPageAuth(app, app.id, pageCodeContext)];
                    case 1:
                        checkAuthResult = _a.sent();
                        setWeDaHasLogin(checkAuthResult);
                        createStateDataSourceVar(page.id, generateParamsParser({ app: app, $page: pageCodeContext }));
                        onRender === null || onRender === void 0 ? void 0 : onRender();
                        return [2 /*return*/];
                }
            });
        }); } }), { app: app, page: pageCodeContext, options: { looseError: options === null || options === void 0 ? void 0 : options.looseError } });
    // 切换页面滚动到顶部
    useScrollTop();
    React.useEffect(function () {
        var _a, _b;
        if (isPure) {
            if (weDaHasLogin) {
                if (!microApp.current) {
                    microApp.current = loadMicroApp({
                        name: page.id,
                        entry: pureSrc,
                        container: containerRef.current,
                    }, {
                        fetch: runtime.fetch,
                    });
                }
                else {
                    (_b = (_a = microApp.current).mount) === null || _b === void 0 ? void 0 : _b.call(_a);
                }
            }
            else if (microApp.current) {
                microApp.current.unmount();
            }
        }
    }, [weDaHasLogin]);
    React.useEffect(function () {
        app.__internal__.activePage = pageCodeContext;
        return function () {
            if (microApp.current) {
                microApp.current.unmount();
            }
        };
    }, []);
    return (React.createElement("div", { ref: containerRef, className: "weapps-page weapps-page-".concat(page.id) },
        React.createElement("style", { type: "text/css", dangerouslySetInnerHTML: {
                __html: "".concat(toCssText(((_c = page.attributes) === null || _c === void 0 ? void 0 : _c.style) || processCommonStyle2CSSProperties(((_d = page === null || page === void 0 ? void 0 : page.extra) === null || _d === void 0 ? void 0 : _d.commonStyle) || {}), 'body')).concat((lowcode.style || []).map(function (item) { return item.code; }).join('\n')),
            } }),
        weDaHasLogin &&
            !isPure &&
            (((_e = lowcode.lifecycle) === null || _e === void 0 ? void 0 : _e.onPageRender) ? ((_f = lowcode.lifecycle) === null || _f === void 0 ? void 0 : _f.onPageRender()) : (React.createElement(AppRender, { virtualFields: virtualFields, componentSchema: componentSchema, codeContext: pageCodeContext, dataContext: dataContext, updateContext: updateContext })))));
}
function initWatchMethods(pageContext) {
    // const { watch = {}, watchState = {}, watchWidget = {}, watchEffects = {}} = pageAPI
    var _a = {}, _b = _a.watch, watch = _b === void 0 ? {} : _b, _c = _a.watchState, watchState = _c === void 0 ? {} : _c, _d = _a.watchWidget, watchWidget = _d === void 0 ? {} : _d, _e = _a.watchEffects, watchEffects = _e === void 0 ? {} : _e;
    // # watch effect
    var watchEffectDisposers = Object.keys(watchEffects).map(function (fnName) {
        return autorun(watchEffects[fnName].bind(pageContext));
    });
    var disposers = watchEffectDisposers;
    // # watch state
    Object.keys(watchState).map(function (key) { return runWatcher(parseWatcher(watchState[key]), pageContext.state, key, 'watchState'); });
    // # watch widgets
    Object.keys(watchWidget).map(function (key) {
        return runWatcher(parseWatcher(watchWidget[key]), pageContext.widgets, key, 'watchWidgets');
    });
    function runWatcher(_a, target, key, label) {
        var _b = _a === void 0 ? {} : _a, handler = _b.handler, immediate = _b.immediate;
        if (!handler) {
            console.error("Invalid ".concat(label, "(").concat(key, ") of ").concat(pageContext.node.widgetType, ", watch must a function or {handler: function}"));
            return;
        }
        var disposer = reaction(function () { return get(target, key); }, handler.bind(pageContext), { fireImmediately: immediate });
        disposers.push(disposer);
    }
}
function parseWatcher(watcher) {
    if (!watcher)
        return;
    if (watcher instanceof Function) {
        return { handler: watcher, immediate: false };
    }
    var handler = watcher.handler, _a = watcher.immediate, immediate = _a === void 0 ? false : _a;
    if (!(handler instanceof Function))
        return;
    return { handler: handler, immediate: immediate };
}
function getPageEvents(componentSchema) {
    var emit = generateEmit();
    return new Proxy({}, {
        get: function (target, eventName) {
            return function (eventData) { return emit(eventName, componentSchema.listenerInstances, eventData, {}, {}, {}, {}); };
        },
    });
}
//# sourceMappingURL=index.js.map