import { BrowserRouter, Navigate, Outlet, Route, Routes } from 'react-router-dom';

import { AppShell } from './components/AppShell';
import { ErrorBoundary } from './components/ErrorBoundary';
import { UpdateToast } from './components/UpdateToast';
import { RequireAdmin, RequireAuth, RequireDevice } from './components/guards';
import { AuthProvider } from './context/AuthContext';
import { CallProvider } from './context/CallContext';
import { ConversationsProvider } from './context/ConversationsContext';
import { FriendshipsProvider } from './context/FriendshipsContext';
import { ThemeProvider } from './context/ThemeContext';
import { AdminPage } from './pages/AdminPage';
import { AuthCallbackPage } from './pages/AuthCallbackPage';
import { AuthPage } from './pages/AuthPage';
import { ChatsEmptyState, ChatsPage } from './pages/ChatsPage';
import { ConversationPage } from './pages/ConversationPage';
import { DevicePage } from './pages/DevicePage';
import { FriendsPage } from './pages/FriendsPage';
import { SettingsPage } from './pages/SettingsPage';

// Isolates each top-level route so a crash in one page doesn't take the whole
// shell down. The boundary auto-retries via `ErrorBoundary`'s backoff schedule.
function RouteBoundary({ scope }: { scope: string }) {
  return (
    <ErrorBoundary scope={scope}>
      <Outlet />
    </ErrorBoundary>
  );
}

export function App() {
  return (
    <ErrorBoundary scope="root">
      <ThemeProvider>
        <AuthProvider>
          <FriendshipsProvider>
            <ConversationsProvider>
              <CallProvider>
                <BrowserRouter
                  future={{
                    // Opt into v7 behaviour early so the upgrade is a no-op:
                    // - `v7_startTransition` wraps navigations in startTransition
                    //   so Suspense / concurrent rendering deal with the new tree
                    // - `v7_relativeSplatPath` matches relative paths inside
                    //   splat routes against the parent splat segment (not the
                    //   full matched path). Our tree has no splat routes today
                    //   but this kills the runtime warning and future-proofs.
                    v7_startTransition: true,
                    v7_relativeSplatPath: true,
                  }}
                >
                  <Routes>
                    <Route element={<RouteBoundary scope="auth" />}>
                      <Route path="/auth" element={<AuthPage />} />
                      <Route path="/auth/callback" element={<AuthCallbackPage />} />
                    </Route>
                    <Route element={<RequireAuth />}>
                      <Route element={<RouteBoundary scope="device" />}>
                        <Route path="/device" element={<DevicePage />} />
                      </Route>
                      <Route element={<RequireDevice />}>
                        <Route element={<AppShell />}>
                          <Route index element={<Navigate to="/chats" replace />} />
                          <Route element={<RouteBoundary scope="chats" />}>
                            <Route path="/chats" element={<ChatsPage />}>
                              <Route index element={<ChatsEmptyState />} />
                              <Route
                                path=":id"
                                element={
                                  <ErrorBoundary scope="conversation">
                                    <ConversationPage />
                                  </ErrorBoundary>
                                }
                              />
                            </Route>
                          </Route>
                          <Route element={<RouteBoundary scope="friends" />}>
                            <Route path="/friends" element={<FriendsPage />} />
                          </Route>
                          <Route element={<RouteBoundary scope="settings" />}>
                            <Route path="/settings" element={<SettingsPage />} />
                          </Route>
                          <Route element={<RequireAdmin />}>
                            <Route element={<RouteBoundary scope="admin" />}>
                              <Route path="/admin" element={<AdminPage />} />
                            </Route>
                          </Route>
                        </Route>
                      </Route>
                    </Route>
                    <Route path="*" element={<Navigate to="/chats" replace />} />
                  </Routes>
                  <UpdateToast />
                </BrowserRouter>
              </CallProvider>
            </ConversationsProvider>
          </FriendshipsProvider>
        </AuthProvider>
      </ThemeProvider>
    </ErrorBoundary>
  );
}
