import { useEffect, useState, type ReactNode } from 'react';
import { useDispatch } from 'react-redux';
import { PageLoader } from '@ema-platform/ui';
import { authStorage } from '../utils/auth-storage';
import { hydrateAuth, logout, setUser } from '../store/auth.slice';
import type { AuthUser } from '../types/auth.types';

const BASE_API_URL =
  (import.meta as { env?: Record<string, string> }).env?.['VITE_BASE_API_URL'] ??
  'http://localhost:3001/api';

/**
 * Restores the signed-in session before the router renders.
 *
 * Redux starts empty on every page load while the token lives in
 * localStorage, so without this a refresh leaves the app half–signed-in: the
 * route guards see a token and let you through, but pages that read
 * `auth.user` think you are a stranger.
 *
 * A token the server no longer accepts is cleared here rather than left to
 * strand the user on a page they cannot act on or sign out of.
 */
export function AuthBootstrap({ children }: { children: ReactNode }) {
  const dispatch = useDispatch();
  const [ready, setReady] = useState(false);

  useEffect(() => {
    let cancelled = false;

    async function restore() {
      dispatch(hydrateAuth());

      const token = authStorage.getToken();
      const cachedUser = authStorage.getUser<AuthUser>();
      if (!token) {
        if (!cancelled) setReady(true);
        return;
      }

      try {
        const response = await fetch(`${BASE_API_URL}/auth/me`, {
          headers: { Authorization: `Bearer ${token}` },
        });

        if (response.ok) {
          const user = (await response.json()) as AuthUser;
          // Keep the persisted session as the source of truth when it is
          // available. A successful profile update writes it immediately,
          // while `/auth/me` can briefly return a stale read and otherwise
          // undo that update on every page refresh. We still make this call
          // to validate the token and clear invalid sessions below.
          if (!cancelled && !cachedUser) dispatch(setUser(user));
        } else if (response.status === 401 || response.status === 403) {
          // Expired or revoked — drop it so the user gets a login screen
          // instead of a dead end.
          if (!cancelled) dispatch(logout());
        }
      } catch {
        // Offline or the API is down: keep the stored session and let the
        // individual screens surface their own errors.
      } finally {
        if (!cancelled) setReady(true);
      }
    }

    restore();
    return () => {
      cancelled = true;
    };
  }, [dispatch]);

  // Rendering the router before the session resolves would let the guards
  // redirect based on a state that is about to change.
  if (!ready) return <PageLoader />;

  return <>{children}</>;
}
