import React from 'react';
import {
  Outlet,
  Route,
  createBrowserRouter,
  createHashRouter,
  createRoutesFromElements,
  redirect,
} from 'react-router';
import { RoomSkeleton } from '../components/RoomSkeleton';
import { LobbySkeleton } from '../components/LobbySkeleton';
import { AuthSkeleton } from '../components/AuthSkeleton';

import { ClientConfig } from '../hooks/useClientConfig';
import {
  DIRECT_PATH,
  EXPLORE_PATH,
  HOME_PATH,
  LOGIN_PATH,
  INBOX_PATH,
  REGISTER_PATH,
  RESET_PASSWORD_PATH,
  SPACE_PATH,
  _CREATE_PATH,
  _FEATURED_PATH,
  _INVITES_PATH,
  _JOIN_PATH,
  _LOBBY_PATH,
  _NOTIFICATIONS_PATH,
  _ROOM_PATH,
  _SEARCH_PATH,
  _SERVER_PATH,
  CREATE_PATH,
} from './paths';
import {
  getAppPathFromHref,
  getExploreFeaturedPath,
  getHomePath,
  getInboxNotificationsPath,
  getLoginPath,
  getOriginBaseUrl,
  getSpaceLobbyPath,
} from './pathUtils';
import { ClientBindAtoms, ClientLayout, ClientRoot } from './client';
import { Home, HomeRouteRoomProvider, HomeSearch } from './client/home';
import { Direct, DirectCreate, DirectRouteRoomProvider } from './client/direct';
import { RouteSpaceProvider, Space, SpaceRouteRoomProvider, SpaceSearch } from './client/space';

import { setAfterLoginRedirectPath } from './afterLoginRedirectPath';

import { WelcomePage } from './client/WelcomePage';
import { SidebarNav } from './client/SidebarNav';
import { PageRoot } from '../components/page';
import { ScreenSize } from '../hooks/useScreenSize';
import { MobileFriendlyPageNav, MobileFriendlyClientNav } from './MobileFriendly';
import { ClientInitStorageAtom } from './client/ClientInitStorageAtom';
import { ClientNonUIFeatures } from './client/ClientNonUIFeatures';
import { AuthRouteThemeManager, UnAuthRouteThemeManager } from './ThemeManager';
import { ReceiveSelfDeviceVerification } from '../components/DeviceVerification';
import { AutoRestoreBackupOnVerification } from '../components/BackupRestore';
import { ClientRoomsNotificationPreferences } from './client/ClientRoomsNotificationPreferences';
import { UserRoomProfileRenderer } from '../components/UserRoomProfileRenderer';
import { HomeCreateRoom } from './client/home/CreateRoom';
import { Create } from './client/create';
import { getFallbackSession } from '../state/sessions';
import { RouteError } from './RouteError';
import { CallStatusRenderer } from './CallStatusRenderer';
import { CallEmbedProvider } from '../components/CallEmbedProvider';

const AuthLayout = React.lazy(() => import('./auth').then((m) => ({ default: m.AuthLayout })));
const Login = React.lazy(() => import('./auth').then((m) => ({ default: m.Login })));
const Register = React.lazy(() => import('./auth').then((m) => ({ default: m.Register })));
const ResetPassword = React.lazy(() =>
  import('./auth').then((m) => ({ default: m.ResetPassword })),
);
const Room = React.lazy(() => import('../features/room').then((m) => ({ default: m.Room })));
const RoomSettingsRenderer = React.lazy(() =>
  import('../features/room-settings').then((m) => ({ default: m.RoomSettingsRenderer })),
);
const SpaceSettingsRenderer = React.lazy(() =>
  import('../features/space-settings').then((m) => ({ default: m.SpaceSettingsRenderer })),
);
const CreateRoomModalRenderer = React.lazy(() =>
  import('../features/create-room').then((m) => ({ default: m.CreateRoomModalRenderer })),
);
const CreateSpaceModalRenderer = React.lazy(() =>
  import('../features/create-space').then((m) => ({ default: m.CreateSpaceModalRenderer })),
);
const SearchModalRenderer = React.lazy(() =>
  import('../features/search').then((m) => ({ default: m.SearchModalRenderer })),
);
const Explore = React.lazy(() => import('./client/explore').then((m) => ({ default: m.Explore })));
const FeaturedRooms = React.lazy(() =>
  import('./client/explore').then((m) => ({ default: m.FeaturedRooms })),
);
const PublicRooms = React.lazy(() =>
  import('./client/explore').then((m) => ({ default: m.PublicRooms })),
);
const Notifications = React.lazy(() =>
  import('./client/inbox').then((m) => ({ default: m.Notifications })),
);
const Inbox = React.lazy(() => import('./client/inbox').then((m) => ({ default: m.Inbox })));
const Invites = React.lazy(() => import('./client/inbox').then((m) => ({ default: m.Invites })));
const Lobby = React.lazy(() => import('../features/lobby').then((m) => ({ default: m.Lobby })));

export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize) => {
  const { hashRouter } = clientConfig;
  const mobile = screenSize === ScreenSize.Mobile;

  const routes = createRoutesFromElements(
    <Route HydrateFallback={() => null} errorElement={<RouteError />}>
      <Route
        index
        loader={() => {
          if (getFallbackSession()) return redirect(getHomePath());
          const afterLoginPath = getAppPathFromHref(getOriginBaseUrl(), window.location.href);
          if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
          return redirect(getLoginPath());
        }}
      />
      <Route
        loader={() => {
          if (getFallbackSession()) {
            return redirect(getHomePath());
          }

          return null;
        }}
        element={
          <React.Suspense fallback={<AuthSkeleton />}>
            <AuthLayout />
            <UnAuthRouteThemeManager />
          </React.Suspense>
        }
      >
        <Route
          path={LOGIN_PATH}
          element={
            <React.Suspense fallback={null}>
              <Login />
            </React.Suspense>
          }
        />
        <Route
          path={REGISTER_PATH}
          element={
            <React.Suspense fallback={null}>
              <Register />
            </React.Suspense>
          }
        />
        <Route
          path={RESET_PASSWORD_PATH}
          element={
            <React.Suspense fallback={null}>
              <ResetPassword />
            </React.Suspense>
          }
        />
      </Route>

      <Route
        loader={() => {
          const session = getFallbackSession();
          if (!session) {
            const afterLoginPath = getAppPathFromHref(
              getOriginBaseUrl(hashRouter),
              window.location.href,
            );
            if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
            return redirect(getLoginPath());
          }
          return null;
        }}
        element={
          <AuthRouteThemeManager>
            <ClientRoot>
              <ClientInitStorageAtom>
                <ClientRoomsNotificationPreferences>
                  <ClientBindAtoms>
                    <ClientNonUIFeatures>
                      <CallEmbedProvider>
                        <ClientLayout
                          nav={
                            <MobileFriendlyClientNav>
                              <SidebarNav />
                            </MobileFriendlyClientNav>
                          }
                        >
                          <Outlet />
                        </ClientLayout>
                        <CallStatusRenderer />
                      </CallEmbedProvider>
                      <React.Suspense fallback={null}>
                        <SearchModalRenderer />
                      </React.Suspense>
                      <UserRoomProfileRenderer />
                      <React.Suspense fallback={null}>
                        <CreateRoomModalRenderer />
                      </React.Suspense>
                      <React.Suspense fallback={null}>
                        <CreateSpaceModalRenderer />
                      </React.Suspense>
                      <React.Suspense fallback={null}>
                        <RoomSettingsRenderer />
                      </React.Suspense>
                      <React.Suspense fallback={null}>
                        <SpaceSettingsRenderer />
                      </React.Suspense>
                      <ReceiveSelfDeviceVerification />
                      <AutoRestoreBackupOnVerification />
                    </ClientNonUIFeatures>
                  </ClientBindAtoms>
                </ClientRoomsNotificationPreferences>
              </ClientInitStorageAtom>
            </ClientRoot>
          </AuthRouteThemeManager>
        }
      >
        <Route
          path={HOME_PATH}
          element={
            <PageRoot
              nav={
                <MobileFriendlyPageNav path={HOME_PATH}>
                  <Home />
                </MobileFriendlyPageNav>
              }
            >
              <Outlet />
            </PageRoot>
          }
        >
          {mobile ? null : <Route index element={<WelcomePage />} />}
          <Route
            path={_CREATE_PATH}
            element={
              <React.Suspense fallback={null}>
                <HomeCreateRoom />
              </React.Suspense>
            }
          />
          <Route path={_JOIN_PATH} element={<p>join</p>} />
          <Route path={_SEARCH_PATH} element={<HomeSearch />} />
          <Route
            path={_ROOM_PATH}
            element={
              <HomeRouteRoomProvider>
                <React.Suspense fallback={<RoomSkeleton />}>
                  <Room />
                </React.Suspense>
              </HomeRouteRoomProvider>
            }
          />
        </Route>
        <Route
          path={DIRECT_PATH}
          element={
            <PageRoot
              nav={
                <MobileFriendlyPageNav path={DIRECT_PATH}>
                  <Direct />
                </MobileFriendlyPageNav>
              }
            >
              <Outlet />
            </PageRoot>
          }
        >
          {mobile ? null : <Route index element={<WelcomePage />} />}
          <Route path={_CREATE_PATH} element={<DirectCreate />} />
          <Route
            path={_ROOM_PATH}
            element={
              <DirectRouteRoomProvider>
                <React.Suspense fallback={<RoomSkeleton />}>
                  <Room />
                </React.Suspense>
              </DirectRouteRoomProvider>
            }
          />
        </Route>
        <Route
          path={SPACE_PATH}
          element={
            <RouteSpaceProvider>
              <PageRoot
                nav={
                  <MobileFriendlyPageNav path={SPACE_PATH}>
                    <Space />
                  </MobileFriendlyPageNav>
                }
              >
                <Outlet />
              </PageRoot>
            </RouteSpaceProvider>
          }
        >
          {mobile ? null : (
            <Route
              index
              loader={({ params }) => {
                const { spaceIdOrAlias } = params;
                if (spaceIdOrAlias) {
                  return redirect(getSpaceLobbyPath(spaceIdOrAlias));
                }
                return null;
              }}
              element={<WelcomePage />}
            />
          )}
          <Route
            path={_LOBBY_PATH}
            element={
              <React.Suspense fallback={<LobbySkeleton />}>
                <Lobby />
              </React.Suspense>
            }
          />
          <Route path={_SEARCH_PATH} element={<SpaceSearch />} />
          <Route
            path={_ROOM_PATH}
            element={
              <SpaceRouteRoomProvider>
                <React.Suspense fallback={<RoomSkeleton />}>
                  <Room />
                </React.Suspense>
              </SpaceRouteRoomProvider>
            }
          />
        </Route>
        <Route
          path={EXPLORE_PATH}
          element={
            <PageRoot
              nav={
                <MobileFriendlyPageNav path={EXPLORE_PATH}>
                  <React.Suspense fallback={null}>
                    <Explore />
                  </React.Suspense>
                </MobileFriendlyPageNav>
              }
            >
              <Outlet />
            </PageRoot>
          }
        >
          {mobile ? null : (
            <Route
              index
              loader={() => redirect(getExploreFeaturedPath())}
              element={<WelcomePage />}
            />
          )}
          <Route
            path={_FEATURED_PATH}
            element={
              <React.Suspense fallback={null}>
                <FeaturedRooms />
              </React.Suspense>
            }
          />
          <Route
            path={_SERVER_PATH}
            element={
              <React.Suspense fallback={null}>
                <PublicRooms />
              </React.Suspense>
            }
          />
        </Route>
        <Route
          path={CREATE_PATH}
          element={
            <React.Suspense fallback={null}>
              <Create />
            </React.Suspense>
          }
        />
        <Route
          path={INBOX_PATH}
          element={
            <PageRoot
              nav={
                <MobileFriendlyPageNav path={INBOX_PATH}>
                  <React.Suspense fallback={null}>
                    <Inbox />
                  </React.Suspense>
                </MobileFriendlyPageNav>
              }
            >
              <Outlet />
            </PageRoot>
          }
        >
          {mobile ? null : (
            <Route
              index
              loader={() => redirect(getInboxNotificationsPath())}
              element={<WelcomePage />}
            />
          )}
          <Route
            path={_NOTIFICATIONS_PATH}
            element={
              <React.Suspense fallback={null}>
                <Notifications />
              </React.Suspense>
            }
          />
          <Route
            path={_INVITES_PATH}
            element={
              <React.Suspense fallback={null}>
                <Invites />
              </React.Suspense>
            }
          />
        </Route>
      </Route>
      <Route path="/*" element={<p>Page not found</p>} />
    </Route>,
  );

  if (hashRouter?.enabled) {
    return createHashRouter(routes, { basename: hashRouter.basename });
  }
  return createBrowserRouter(routes, {
    basename: import.meta.env.BASE_URL,
  });
};
