import React from 'react';
import { Switch, Redirect, Route, RouteProps } from 'react-router-dom';

import { CosmosRouterProps } from './type';
import { routeContext, flatRoutes, addFlag2Route, filterAuthedRoute } from './utils';
import { LazyComponent } from './components/LazyComponent';
import { LayoutWrapper } from './components/LayoutWrapper';

const { Provider } = routeContext;

export function CosmosRouter<Extend extends Record<string, unknown> = {}, Auth = number>(props: CosmosRouterProps<Extend, Auth>) {
  const {
    routes = [], defaultConfig, lazyLoad, layout,
    checkAuth, catalogFromRoute, hasCheckResult
  } = props;

  const authFlagRoutes = addFlag2Route(routes, checkAuth);

  return (
    <Provider value={{ routes: filterAuthedRoute(authFlagRoutes), defaultConfig }}>
      <Switch>
        {
          flatRoutes(authFlagRoutes)
            .filter(({ authFlag }) => !hasCheckResult || authFlag)
            .map(route => {
              const {
                path, redirectTo, auth, authFlag, useLayout, fallback,
                exist, children, noAuthDisplay, catalog, allCatalog, 
                allPath, component, render, ...rest
              } = {
                exact: true,
                useLayout: true,
                ...defaultConfig,
                ...route
              };

              // 是否使用布局
              const hasLayout = !!(useLayout && layout);

              if (!authFlag) {
                // 旧版本这里使用的是 fallback， 这里做一下兼容
                const noAuthNode = noAuthDisplay || fallback || null;

                return (
                  <Route<RouteProps>
                    key={allPath}
                    path={allPath}
                    {...rest}
                  >
                    {
                      hasLayout ?
                        <LayoutWrapper layout={layout!}>{noAuthNode}</LayoutWrapper> :
                        noAuthNode
                    }
                  </Route>
                );
              }

              // 重定向
              if (redirectTo) {
                return (
                  <Redirect key={allPath} path={allPath} to={redirectTo} exact />
                );
              }

              // 非自动懒加载组件的情况
              if (component || render) {
                return hasLayout ? (
                  <Route<RouteProps> key={allPath}
                    path={allPath}
                    {...rest}
                  >
                    <LayoutWrapper layout={layout!}
                      component={component}
                      render={render}
                    />
                  </Route>
                ) : (
                    <Route key={allPath} path={allPath} {...rest as any} />
                  )
              }


              const lazyComp = typeof lazyLoad === 'function' ? (
                <LazyComponent lazyLoad={() => lazyLoad(catalogFromRoute ? allCatalog : catalog!)}
                  fallback={fallback}
                />
              ) : null;

              return (
                <Route<RouteProps>
                  key={allPath}
                  path={allPath}
                  {...rest}
                >
                  {
                    hasLayout ?
                      <LayoutWrapper layout={layout!}>{lazyComp}</LayoutWrapper> :
                      lazyComp
                  }
                </Route>
              )
            })
        }
      </Switch>
    </Provider>
  )
};