/**
 * @file ProtectedRoute.tsx - Route guard that protects authenticated-only routes.
 * If the user is not authenticated (no username/token in AuthContext), they are redirected to /login with the current location preserved for post-login navigation.
 * While a cross-tab session sync is in progress (isInitializing), a loading spinner is shown to prevent a flash of the login page.
 */

import type { ReactNode } from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext.tsx';
import { useTranslation } from 'react-i18next';
import { Spinner } from 'react-bootstrap';
import { getAccessToken } from '../services/authService.ts';

/** Props for the ProtectedRoute wrapper component. */
interface ProtectedRouteProps {
  /** The child route content to render when the user is authenticated */
  children: ReactNode;
}

/**
 * Route guard component that conditionally renders its children based on the user's authentication state.
 */
export const ProtectedRoute = ({ children }: ProtectedRouteProps) => {
  const { username, token, isInitializing } = useAuth();
  const location = useLocation();

  // While the auth context is syncing session data across tabs, show a spinner
  // (or render nothing if no token exists, so the login redirect happens immediately)
  if (isInitializing) {
    if (!getAccessToken()) {
      return null;
    }
    return <LoadingSpinner />;
  }

  // Redirect unauthenticated users to login, preserving the intended destination
  if (!username || !token) {
    return <Navigate to={'/login'} state={{ from: location }} />;
  }

  return <>{children}</>;
};

/**
 * Full-page centered loading spinner shown while the cross-tab session sync is in progress.
 */
const LoadingSpinner = () => {
  const { t } = useTranslation(undefined, {
    keyPrefix: 'components.protected_route.loading_spinner',
  });

  return (
    <div
      className={
        'd-flex flex-column gap-2 justify-content-center align-items-center flex-grow-1'
      }
    >
      <Spinner animation={'border'} role={'status'} variant={'primary'}>
        <span className={'visually-hidden'}>{t('spinner.default')}...</span>
      </Spinner>
      <div>{t('text')}...</div>
    </div>
  );
};
