import { createElement, ReactType, ReactElement } from 'react';
import ReactDOM from 'react-dom';
import { Router } from '@recore/router';
import { app, Provider } from '@ali/lowcode-runtime';
import { AppHelper } from '@ali/lowcode-utils';
import LazyComponent from './components/LazyComponent';

export default class ReactProvider extends Provider {
  // 定制构造根组件的逻辑，如切换路由机制
  createApp() {
    let RouterView = this.getRouterView();
    let App: any;
    const layoutConfig = this.getLayoutConfig();
    if (!layoutConfig || !layoutConfig.componentName) {
      App = (props: any) => (RouterView ? createElement(RouterView, { ...props }) : null);
      return App;
    }
    const { componentName: layoutName, props: layoutProps } = layoutConfig;
    const { content: Layout, props: extraLayoutProps } = app.getLayout(layoutName) || {};
    const sectionalRender = this.isSectionalRender;
    if (!sectionalRender && Layout) {
      App = (props: any) =>
        createElement(
          Layout,
          { ...layoutProps, ...extraLayoutProps },
          RouterView ? createElement(RouterView, props) : null,
        );
    } else {
      App = (props: any) => (RouterView ? createElement(RouterView, props) : null);
    }
    return App;
  }

  runApp(App: any, config: any) {
    const containerId = config?.containerId || 'App';
    let container = document.getElementById(containerId);
    if (!container) {
      container = document.createElement('div');
      document.body.appendChild(container);
      container.id = containerId;
    }
    ReactDOM.render(<App />, container);
  }

  // 内置实现 for 动态化渲染
  getRouterView(): ReactType {
    const routerConfig = this.getRouterConfig();
    if (!routerConfig) {
      return () => null;
    }
    const routes: Array<{
      path: string;
      children: any;
      exact: boolean;
      defined: { keepAlive: boolean; [key: string]: any };
    }> = [];
    let homePageId = this.getHomePage();
    Object.keys(routerConfig).forEach((pageId: string, idx: number) => {
      if (!pageId) {
        return;
      }
      const path = routerConfig[pageId];
      routes.push({
        path,
        children: (props: any) => this.getLazyComponent(pageId, props),
        exact: true,
        defined: { keepAlive: true },
      });
      if (homePageId) {
        return;
      }
      if (idx === 0 || path === '/') {
        homePageId = pageId;
      }
    });
    if (homePageId) {
      routes.push({
        path: '**',
        children: (props: any) => this.getLazyComponent(homePageId, { ...props }),
        exact: true,
        defined: { keepAlive: true },
      });
    }
    const appHelper = new AppHelper();
    appHelper.set('utils', this.getUtils());
    appHelper.set('constants', this.getConstants());
    const RouterView = (props: any) => {
      return createElement(Router as any, {
        routes,
        components: this.getComponents(),
        utils: this.getUtils(),
        appHelper,
        componentsMap: this.getComponentsMapObj(),
        ...props,
      });
    };
    return RouterView;
  }

  getLazyComponent(pageId: string, props: any): ReactElement | null {
    if (!pageId) {
      return null;
    }
    if (this.getLazyElement(pageId)) {
      return this.getLazyElement(pageId);
    } else {
      const lazyElement = createElement(LazyComponent as any, {
        getPageData: async () => await this.getPageData(pageId),
        key: pageId,
        context: this,
        ...props,
      });
      this.setLazyElement(pageId, lazyElement);
      return lazyElement;
    }
  }
}
