// src/auth/AuthProvider.jsx
//
// Staff-plane auth — NO Gateway session exchange.
// MSAL acquires a JWT from the org tenant; that JWT is sent directly to
// Management API as a Bearer token on every request. No session token exists.
//
import React, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
import { PublicClientApplication, InteractionStatus } from '@azure/msal-browser';
import { MsalProvider, useMsal, useIsAuthenticated } from '@azure/msal-react';
import { msalConfig, loginRequest } from './authConfig';

const msalInstance = new PublicClientApplication(msalConfig);

msalInstance.initialize().then(() => {
  msalInstance.handleRedirectPromise().catch(console.error);
});

const AuthContext = createContext(null);

export function useAuth() {
  const context = useContext(AuthContext);
  if (!context) throw new Error('useAuth must be used within an AuthProvider');
  return context;
}

function AuthProviderInner({ children }) {
  const { instance, accounts, inProgress } = useMsal();
  const isAuthenticated = useIsAuthenticated();

  const [accessToken, setAccessToken] = useState(null);
  const [sessionUser, setSessionUser] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);
  const initialized = useRef(false);

  const account = accounts[0] || null;

  // Acquire MSAL token silently and store it — no Gateway exchange.
  const initializeSession = useCallback(async () => {
    if (!account) { setIsLoading(false); return; }
    try {
      setIsLoading(true);
      setError(null);

      const tokenResponse = await instance.acquireTokenSilent({
        ...loginRequest,
        account,
      });

      const jwt = tokenResponse.accessToken;
      setAccessToken(jwt);
      setSessionUser({
        email: account.username,
        name:  account.name,
      });
      sessionStorage.setItem('adp_access_token', jwt);
    } catch (err) {
      console.error('[Auth] Token acquisition error:', err);
      setError('Please sign in again');
    } finally {
      setIsLoading(false);
    }
  }, [account, instance]);

  // On mount: restore from sessionStorage or acquire fresh.
  useEffect(() => {
    if (initialized.current) return;
    if (inProgress !== InteractionStatus.None) return;
    initialized.current = true;

    const stored = sessionStorage.getItem('adp_access_token');
    if (stored) {
      // Optimistically restore — MSAL will silently refresh when it expires.
      setAccessToken(stored);
      setSessionUser({ email: account?.username, name: account?.name });
      setIsLoading(false);
    } else if (isAuthenticated) {
      initializeSession();
    } else {
      // No account and no stored token — redirect straight to Microsoft login.
      // Skips the app's own login screen entirely.
      instance.loginRedirect(loginRequest).catch(err => {
        console.error('[Auth] Auto-redirect failed:', err);
        setIsLoading(false);
      });
    }
  }, [isAuthenticated, inProgress, initializeSession, account, instance]);

  const signIn = useCallback(async () => {
    try {
      setError(null);
      await instance.loginRedirect(loginRequest);
    } catch (err) {
      console.error('[Auth] Sign in error:', err);
      setError(err.message);
    }
  }, [instance]);

  const signOut = useCallback(async () => {
    try {
      sessionStorage.removeItem('adp_access_token');
      setAccessToken(null);
      setSessionUser(null);
      await instance.logoutRedirect();
    } catch (err) {
      console.error('[Auth] Sign out error:', err);
    }
  }, [instance]);

  // Acquire a fresh token (MSAL handles caching/refresh automatically).
  const refreshSession = useCallback(async () => {
    await initializeSession();
  }, [initializeSession]);

  // Both helpers return the same MSAL JWT — Management API only needs Bearer.
  const getAccessToken = useCallback(async () => {
    if (!account) return null;
    try {
      const resp = await instance.acquireTokenSilent({ ...loginRequest, account });
      return resp.accessToken;
    } catch {
      return accessToken;
    }
  }, [account, instance, accessToken]);

  // Alias kept so components that call getIdToken() continue to work.
  const getIdToken = getAccessToken;

  const value = {
    isAuthenticated: !!accessToken,
    isLoading: isLoading || inProgress !== InteractionStatus.None,
    error,
    account,
    sessionUser,
    sessionToken: accessToken,  // alias — components reading sessionToken get the JWT
    signIn,
    signOut,
    refreshSession,
    getIdToken,
    getAccessToken,
    clearError: () => setError(null),
  };

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

export function AuthProvider({ children }) {
  return (
    <MsalProvider instance={msalInstance}>
      <AuthProviderInner>
        {children}
      </AuthProviderInner>
    </MsalProvider>
  );
}
