import React, { FC, Suspense } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
import { ThemeProvider, theme } from '@polymathnetwork/polymesh-ui';
import { StaticPage } from './StaticPage';
import { DefaultPage } from './StaticPages';
import { Api as DefaultApi } from './Api';
import {
  AppStaticRoute,
  AppBaseReduxConfig,
  ApiConfig,
  StaticRoutes,
} from './definition';

const MainApp: FC<{
  appName: string;
  Api: any;
  apiConfig: ApiConfig;
  Routes: any;
  redux: AppBaseReduxConfig;
  routeProps?: any;
}> = ({ appName, Api, apiConfig, Routes, redux, routeProps }) => {
  return (
    <redux.provider store={redux.store}>
      <Api appName={appName} apiConfig={apiConfig} redux={redux}>
        <Routes {...routeProps} />
      </Api>
    </redux.provider>
  );
};

export interface AppBaseProps {
  appName: string;
  mainPath: string;
  Routes: any;
  staticRoutes?: StaticRoutes;
  redux: AppBaseReduxConfig;
  onError: (error: Error) => void;
  StyleFixes?: any;
  Api?: any;
  apiConfig: ApiConfig;
  ErrorBoundaryPage?: FC<FallbackProps>;
}

export const AppBase: FC<AppBaseProps> = ({
  Api = DefaultApi,
  apiConfig,
  appName,
  mainPath,
  Routes,
  staticRoutes,
  redux,
  onError,
  StyleFixes,
  ErrorBoundaryPage = ({ error }) => (
    <DefaultPage
      appName={appName}
      mainPath={mainPath}
      body={error?.message || 'ErrorBoundary: Something went wrong'}
    />
  ),
}) => {
  const combinedStaticRoutes = [
    ...Object.values(AppStaticRoute),
    ...Object.keys(staticRoutes || {}),
  ];

  const onReset = () => {
    window.location.reload();
  };

  return (
    <Suspense fallback="...">
      <ThemeProvider theme={theme}>
        {!!StyleFixes && <StyleFixes />}
        <ErrorBoundary
          onError={onError}
          onReset={onReset}
          FallbackComponent={ErrorBoundaryPage}
        >
          <Router>
            <Switch>
              <Route
                path={combinedStaticRoutes}
                exact
                render={(routeProps: any) => (
                  <StaticPage
                    routeProps={routeProps}
                    appName={appName}
                    mainPath={mainPath}
                    staticRoutes={staticRoutes}
                    apiConfig={apiConfig}
                  />
                )}
              />
              <Route
                path="/:path"
                render={(routeProps: any) => (
                  <MainApp
                    routeProps={routeProps}
                    appName={appName}
                    Api={Api}
                    apiConfig={apiConfig}
                    Routes={Routes}
                    redux={redux}
                  />
                )}
              />
            </Switch>
          </Router>
        </ErrorBoundary>
      </ThemeProvider>
    </Suspense>
  );
};
