import { jsx } from "react/jsx-runtime";
import react from "react";
import { define as schema_define, observable } from "@tachybase/schema";
import { getRequireJs, getSubAppName } from "@tego/client";
import { get, merge, set } from "lodash";
import { createRoot } from "react-dom/client";
import { I18nextProvider } from "react-i18next";
import { Link, NavLink, Navigate } from "react-router-dom";
import { APIClient, APIClientProvider } from "../api-client/index.mjs";
import { CollectionField } from "../data-source/collection-field/CollectionField.mjs";
import { DataSourceApplicationProvider } from "../data-source/components/DataSourceApplicationProvider.mjs";
import { DataBlockProvider } from "../data-source/data-block/DataBlockProvider.mjs";
import { DataSourceManager } from "../data-source/data-source/DataSourceManager.mjs";
import { i18n } from "../i18n/index.mjs";
import { CSSVariableProvider } from "../style/css-variable/index.mjs";
import { AntdAppProvider, GlobalThemeProvider } from "../style/theme/index.mjs";
import { AppSchemaComponentProvider } from "./AppSchemaComponentProvider.mjs";
import { AttachmentPreviewManager } from "./AttachmentPreviewManager.mjs";
import { AppComponent, BlankComponent, defaultAppComponents } from "./components/index.mjs";
import { NoticeManager } from "./NoticesManager.mjs";
import { PluginContextMenu } from "./PluginContextMenu.mjs";
import { PluginManager } from "./PluginManager.mjs";
import { RouterManager } from "./RouterManager.mjs";
import { SchemaInitializerManager } from "./schema-initializer/index.mjs";
import { SchemaSettingsManager } from "./schema-settings/index.mjs";
import { SystemSettingsManager } from "./SystemSettingsManager.mjs";
import { TrackingManager } from "./TrackingManager.mjs";
import { UserSettingsManager } from "./UserSettingsManager.mjs";
import { compose, normalizeContainer } from "./utils/index.mjs";
import { defineGlobalDeps } from "./utils/globalDeps.mjs";
import { WebSocketClient } from "./WebSocketClient.mjs";
import * as __WEBPACK_EXTERNAL_MODULE__schema_initializer_components_index_mjs_f4ae82ee__ from "./schema-initializer/components/index.mjs";
function _define_property(obj, key, value) {
    if (key in obj) Object.defineProperty(obj, key, {
        value: value,
        enumerable: true,
        configurable: true,
        writable: true
    });
    else obj[key] = value;
    return obj;
}
class Application {
    get pm() {
        return this.pluginManager;
    }
    get adminUrl() {
        if ('main' === this.name) return '/admin/';
        return "/apps/".concat(this.name, "/admin/");
    }
    initRequireJs() {
        this.requirejs = getRequireJs();
        defineGlobalDeps(this.requirejs);
        window.define = this.requirejs.define;
        window.require = this.requirejs.require;
    }
    addDefaultProviders() {
        this.use(APIClientProvider, {
            apiClient: this.apiClient
        });
        this.use(I18nextProvider, {
            i18n: this.i18n
        });
        this.use(GlobalThemeProvider);
        this.use(CSSVariableProvider);
        this.use(AppSchemaComponentProvider, {
            designable: this.options.designable,
            appName: this.name,
            components: this.components,
            scope: this.scopes
        });
        this.use(AntdAppProvider);
        this.use(DataSourceApplicationProvider, {
            dataSourceManager: this.dataSourceManager
        });
    }
    addReactRouterComponents() {
        this.addComponents({
            Link: Link,
            Navigate: Navigate,
            NavLink: NavLink
        });
    }
    addRoutes() {
        this.router.add('not-found', {
            path: '*',
            Component: this.components['AppNotFound']
        });
        this.router.add('share.notAuthorized', {
            path: '/share/not-authorized',
            element: null
        });
    }
    getOptions() {
        return this.options;
    }
    getPublicPath() {
        return this.options.publicPath || '/';
    }
    getName() {
        return getSubAppName(this.getPublicPath()) || null;
    }
    getApiUrl() {
        let pathname = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : '';
        let baseURL = this.apiClient.axios['defaults']['baseURL'];
        if (!baseURL.startsWith('http://') && !baseURL.startsWith('https://')) {
            const { protocol, host } = window.location;
            baseURL = "".concat(protocol, "//").concat(host).concat(baseURL);
        }
        return baseURL.replace(/\/$/g, '') + '/' + pathname.replace(/^\//g, '');
    }
    getRouteUrl(pathname) {
        return this.options.publicPath.replace(/\/$/g, '') + pathname;
    }
    getHref(pathname) {
        const name = this.name;
        if (name && 'main' !== name) return this.getPublicPath() + 'apps/' + name + '/' + pathname.replace(/^\//g, '');
        return this.getPublicPath() + pathname.replace(/^\//g, '');
    }
    getCollectionManager(dataSource) {
        var _this_dataSourceManager_getDataSource;
        return null == (_this_dataSourceManager_getDataSource = this.dataSourceManager.getDataSource(dataSource)) ? void 0 : _this_dataSourceManager_getDataSource.collectionManager;
    }
    getComposeProviders() {
        const Providers = compose(...this.providers)(BlankComponent);
        Providers.displayName = 'Providers';
        return Providers;
    }
    use(component, props) {
        return this.addProvider(component, props);
    }
    addProvider(component, props) {
        return this.providers.push([
            component,
            props
        ]);
    }
    addProviders(providers) {
        providers.forEach((provider)=>{
            if (Array.isArray(provider)) this.addProvider(provider[0], provider[1]);
            else this.addProvider(provider);
        });
    }
    async load() {
        let loadFailed = false;
        this.ws.on('message', (event)=>{
            var _data_payload;
            const data = JSON.parse(event.data);
            if (null == data ? void 0 : null == (_data_payload = data.payload) ? void 0 : _data_payload.refresh) return void window.location.reload();
            if ('notification' === data.type) {
                var _data_payload1, _data_payload2;
                this.notification[(null == (_data_payload1 = data.payload) ? void 0 : _data_payload1.type) || 'info']({
                    message: null == (_data_payload2 = data.payload) ? void 0 : _data_payload2.message
                });
                return;
            }
            if ('notice' === data.type) this.noticeManager.on(data.payload);
            const maintaining = 'maintaining' === data.type && 'APP_RUNNING' !== data.payload.code;
            if (maintaining) {
                this.maintaining = true;
                this.error = data.payload;
            } else {
                if (loadFailed) return void window.location.reload();
                this.maintaining = false;
                this.maintained = true;
                this.error = null;
            }
        });
        this.ws.on('serverDown', ()=>{
            this.maintaining = true;
            this.maintained = true;
        });
        this.ws.connect();
        try {
            this.loading = true;
            await this.pm.load();
        } catch (error) {
            var _error_response_data, _error_response, _error_response_data_errors, _error_response_data1, _error_response1;
            if (this.ws.enabled) await new Promise((resolve)=>{
                setTimeout(()=>resolve(null), 1000);
            });
            loadFailed = true;
            const others = (null == error ? void 0 : null == (_error_response = error.response) ? void 0 : null == (_error_response_data = _error_response.data) ? void 0 : _error_response_data.error) || (null == error ? void 0 : null == (_error_response1 = error.response) ? void 0 : null == (_error_response_data1 = _error_response1.data) ? void 0 : null == (_error_response_data_errors = _error_response_data1.errors) ? void 0 : _error_response_data_errors[0]) || {
                message: null == error ? void 0 : error.message
            };
            this.error = {
                code: 'LOAD_ERROR',
                ...others
            };
            console.error(error, this.error);
        }
        this.loading = false;
    }
    getComponent(Component) {
        let isShowError = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : true;
        const showError = (msg)=>isShowError && console.error(msg);
        if (!Component) return void showError("getComponent called with ".concat(Component));
        if ('function' == typeof Component) return Component;
        if ('string' == typeof Component) {
            const res = get(this.components, Component);
            if (!res) return void showError("Component ".concat(Component, " not found"));
            return res;
        }
        showError("Component ".concat(Component, " should be a string or a React component"));
    }
    renderComponent(Component, props) {
        return /*#__PURE__*/ react.createElement(this.getComponent(Component), props);
    }
    addComponent(component, name) {
        const componentName = name || component.displayName || component.name;
        if (!componentName) return void console.error('Component must have a displayName or pass name as second argument');
        set(this.components, componentName, component);
    }
    addComponents(components) {
        Object.keys(components).forEach((name)=>{
            this.addComponent(components[name], name);
        });
    }
    addScopes(scopes) {
        this.scopes = merge(this.scopes, scopes);
    }
    getRootComponent() {
        const Root = ()=>/*#__PURE__*/ jsx(AppComponent, {
                app: this
            });
        return Root;
    }
    mount(containerOrSelector) {
        const container = normalizeContainer(containerOrSelector);
        if (!container) return;
        const App = this.getRootComponent();
        const root = createRoot(container);
        root.render(/*#__PURE__*/ jsx(App, {}));
        return root;
    }
    addFieldInterfaceComponentOption(fieldName, componentOption) {
        return this.dataSourceManager.collectionFieldInterfaceManager.addFieldInterfaceComponentOption(fieldName, componentOption);
    }
    addGlobalVar(key, value) {
        set(this.globalVars, key, value);
    }
    getGlobalVar(key) {
        return get(this.globalVars, key);
    }
    constructor(options = {}){
        _define_property(this, "options", void 0);
        _define_property(this, "providers", void 0);
        _define_property(this, "router", void 0);
        _define_property(this, "scopes", void 0);
        _define_property(this, "i18n", void 0);
        _define_property(this, "ws", void 0);
        _define_property(this, "apiClient", void 0);
        _define_property(this, "components", void 0);
        _define_property(this, "pluginManager", void 0);
        _define_property(this, "systemSettingsManager", void 0);
        _define_property(this, "userSettingsManager", void 0);
        _define_property(this, "devDynamicImport", void 0);
        _define_property(this, "requirejs", void 0);
        _define_property(this, "notification", void 0);
        _define_property(this, "schemaInitializerManager", void 0);
        _define_property(this, "schemaSettingsManager", void 0);
        _define_property(this, "dataSourceManager", void 0);
        _define_property(this, "noticeManager", void 0);
        _define_property(this, "trackingManager", void 0);
        _define_property(this, "pluginContextMenu", void 0);
        _define_property(this, "AttachmentPreviewManager", void 0);
        _define_property(this, "name", void 0);
        _define_property(this, "globalVars", void 0);
        _define_property(this, "loading", void 0);
        _define_property(this, "maintained", void 0);
        _define_property(this, "maintaining", void 0);
        _define_property(this, "error", void 0);
        this.options = options;
        this.providers = [];
        this.scopes = {};
        this.components = {
            DataBlockProvider: DataBlockProvider,
            ...defaultAppComponents,
            ...__WEBPACK_EXTERNAL_MODULE__schema_initializer_components_index_mjs_f4ae82ee__,
            CollectionField: CollectionField
        };
        this.globalVars = {};
        this.loading = true;
        this.maintained = false;
        this.maintaining = false;
        this.error = null;
        this.initRequireJs();
        schema_define(this, {
            maintained: observable.ref,
            loading: observable.ref,
            maintaining: observable.ref,
            error: observable.ref
        });
        this.devDynamicImport = options.devDynamicImport;
        this.scopes = merge(this.scopes, options.scopes);
        this.components = merge(this.components, options.components);
        this.apiClient = options.apiClient instanceof APIClient ? options.apiClient : new APIClient(options.apiClient);
        this.apiClient.app = this;
        this.i18n = options.i18n || i18n;
        this.router = new RouterManager(options.router, this);
        this.schemaSettingsManager = new SchemaSettingsManager(options.schemaSettings, this);
        this.pluginManager = new PluginManager(options.plugins, options.loadRemotePlugins, this);
        this.schemaInitializerManager = new SchemaInitializerManager(options.schemaInitializers, this);
        this.dataSourceManager = new DataSourceManager(options.dataSourceManager, this);
        this.noticeManager = new NoticeManager(this);
        this.trackingManager = new TrackingManager(this);
        this.addDefaultProviders();
        this.addReactRouterComponents();
        this.addProviders(options.providers || []);
        this.ws = new WebSocketClient(options.ws, this);
        this.systemSettingsManager = new SystemSettingsManager(options.pluginSettings, this);
        this.userSettingsManager = new UserSettingsManager(options.userSettings, this);
        this.addRoutes();
        this.name = this.options.name || getSubAppName(options.publicPath) || 'main';
        this.pluginContextMenu = new PluginContextMenu(options.pluginMenuItems);
        this.AttachmentPreviewManager = new AttachmentPreviewManager(options.attachmentItem, this);
        this.i18n.on('languageChanged', (lng)=>{
            this.apiClient.auth.locale = lng;
        });
    }
}
export { Application };
