import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Route, Switch, Redirect, useLocation } from 'react-router-dom';
import Footer from './components/Footer';
import UI from './config/ui/config';
import AddressesPage from './containers/AddressesPage';
import LoginPage from './containers/LoginPage';
import MyDataPage from './containers/MyDataPage';
import MyParcelsPage from './containers/MyParcelsPage';
import ParcelPage from './containers/ParcelPage';
import ShippingPage from './containers/ShippingPage';
import OfflinePage from './containers/OfflinePage';
import DOIPage from './containers/DOIPage';
import UserManagementPage from './containers/UserManagementPage';
import SearchPage from './containers/SearchPage';
import OpenDataPage from './containers/OpenDataPage';
import ClosedDataPage from './containers/ClosedDataPage';
import DatasetsPage from './containers/DatasetsPage';
import EventTagPage from './containers/EventTagPage';
import EventsPage from './containers/EventsPage';
import SelectionPage from './containers/Selection/SelectionPage';
import CameraPage from './containers/CameraPage';
import DataStatisticsPage from './containers/DataStatisticsPage';
import MintSelectionPage from './containers/Selection/MintSelectionPage';
import BeamlineDataPage from './containers/BeamlineDataPage';
import { getRemainingSessionTime } from './helpers/auth';
import { doLogOut, doSilentRefreshFromSSO } from './actions/login';
import keycloak from './config/sso/keycloak';
import Menu from './components/Menu/Menu';
import { fetchAllInvestigations } from './actions/investigations';
import { fetchDataCollections } from './actions/datacollections';
import { useQuery } from './helpers/hooks';
import PageNotFound from './containers/PageNotFound';

function App() {
  const user = useSelector((state) => state.user);

  const location = useLocation();
  const query = useQuery();
  const toParam = query.has('to')
    ? decodeURIComponent(query.get('to'))
    : undefined;

  const dispatch = useDispatch();

  useEffect(() => {
    if (user.sessionId) {
      dispatch(fetchAllInvestigations(user.sessionId));
      dispatch(fetchDataCollections(user.sessionId));
    }
  }, [dispatch, user.sessionId]);

  useEffect(() => {
    if (!user.expirationTime) {
      return;
    }

    /* Set up timer to refresh session or log out user 1 minute before session expires.
     * Needed because ICAT lets requests with expired session IDs hang instead of
     * responding with 401s: https://gitlab.esrf.fr/icat/icat-plus/-/issues/163 */
    const timeout = setTimeout(() => {
      dispatch(
        keycloak && keycloak.authenticated && user.isSSO
          ? doSilentRefreshFromSSO()
          : doLogOut({ expired: true })
      );
    }, getRemainingSessionTime(user.expirationTime) - 60 * 1000);

    return () => {
      // Stop timer when `expirationTime` is cleared or updated (i.e. when user logs out manually, or when session is refreshed)
      clearTimeout(timeout);
    };
  }, [dispatch, user.expirationTime, user.isSSO]);

  if (UI.status.offline.enabled) {
    return <OfflinePage />;
  }

  if (!user.sessionId) {
    return (
      <Switch>
        <Route path="/login">
          <div className="app">
            <Menu />
            <LoginPage />
          </div>
          <Footer />
        </Route>
        <Route>
          <Redirect to={{ pathname: '/login', state: { from: location } }} />
        </Route>
      </Switch>
    );
  }

  return (
    <Switch>
      <Route
        path="/investigation/:investigationId/camera"
        component={CameraPage}
      />

      <Route path="/">
        <div className="app">
          <Menu />

          <Switch>
            <Route
              exact
              path={['/', '/home', '/investigations']}
              component={MyDataPage}
            />

            <Route exact path="/search" component={SearchPage} />
            <Route
              exact
              path="/usermanagement"
              component={UserManagementPage}
            />

            <Route exact path="/public" component={OpenDataPage} />
            <Route exact path="/public/:prefix/:suffix" component={DOIPage} />

            <Route exact path="/closed" component={ClosedDataPage} />
            <Route exact path="/beamline/:id" component={BeamlineDataPage} />

            {UI.sampleTracking.enabled && (
              <Route exact path="/parcels" component={MyParcelsPage} />
            )}
            {UI.sampleTracking.enabled && (
              <Route exact path="/addresses" component={AddressesPage} />
            )}

            <Route
              exact
              path="/investigation/:investigationId/datasets"
              render={({ match }) =>
                UI.investigationContainer.isDatasetListVisible ? (
                  <DatasetsPage />
                ) : (
                  <Redirect
                    to={`/investigation/${match.params.investigationId}/events`}
                  />
                )
              }
            />

            <Route
              exact
              path="/investigation/:investigationId/events/tagManager"
              component={EventTagPage}
            />
            <Route
              exact
              path="/investigation/:investigationId/events"
              component={EventsPage}
            />
            {UI.sampleTracking.enabled && (
              <Route
                exact
                path="/investigation/:investigationId/shipping"
                component={ShippingPage}
              />
            )}
            <Route
              exact
              path="/investigation/:investigationId/parcel/:parcelId"
              component={ParcelPage}
            />

            <Route exact path="/selection" component={SelectionPage} />
            <Route exact path="/selection/mint" component={MintSelectionPage} />

            <Route exact path="/manager/stats" component={DataStatisticsPage} />

            <Route exact path="/login">
              <Redirect
                to={
                  // Redirect users back to where they were before logging in:
                  // - for form or anonymous login, look in location state (cf. `/login` redirect above)
                  // - for SSO login, look in `to` query param (cf. `redirectUri` option in `src/components/SSO.js`)
                  location.state?.from ?? toParam ?? '/'
                }
              />
            </Route>

            <Route>
              <PageNotFound />
            </Route>
          </Switch>
        </div>
        <Footer />
      </Route>
    </Switch>
  );
}

export default App;
