import { createContext, useContext, useState, useEffect, useCallback } from 'react';
import { PublicClientApplication } from '@azure/msal-browser';
import { MsalProvider, useMsal } from '@azure/msal-react';
import { msalConfig, loginRequest, MGMT_SCOPE } from './authConfig';

// ─── MSAL instance (singleton) ───
const msalInstance = new PublicClientApplication(msalConfig);
const msalReady = msalInstance.initialize();

// ─── Context ─────────────────────────────────────────────────────────────────
const AuthContext = createContext(null);
export const useAuth = () => useContext(AuthContext);

// ─── Decode roles from a JWT access token ────────────────────────────────────
function extractRole(accessToken) {
  try {
    const payload = JSON.parse(atob(accessToken.split('.')[1]));
    const roles = payload.roles || [];
    if (roles.includes('Staff.Admin')) return 'Admin';
    if (roles.includes('Staff.Tech'))  return 'Tech';
    return null;
  } catch {
    return null;
  }
}

// ─── Inner provider (needs useMsal) ──────────────────────────────────────────
function AuthInner({ children }) {
  const { instance } = useMsal();

  const [authState,   setAuthState]   = useState('authenticating');
  const [sessionUser, setSessionUser] = useState(null);
  const [userRole,    setUserRole]    = useState(null); // 'Admin' | 'Tech' | null

  const buildUser = (account, role = null) => ({
    userId:      account.localAccountId,
    email:       account.username,
    displayName: account.name || account.username,
    role,
  });

  // Eagerly acquire access token to extract role from claims
  async function resolveRole(account) {
    try {
      const result = await instance.acquireTokenSilent({ scopes: [MGMT_SCOPE], account });
      return extractRole(result.accessToken);
    } catch {
      return null;
    }
  }

  // ─── Init: handle redirect result or restore active account ─────────────
  useEffect(() => {
    let cancelled = false;

    async function init() {
      await msalReady;

      try {
        const response = await instance.handleRedirectPromise();
        if (response?.account && !cancelled) {
          instance.setActiveAccount(response.account);
          const role = await resolveRole(response.account);
          if (cancelled) return;
          setUserRole(role);
          setSessionUser(buildUser(response.account, role));
          setAuthState('active');
          return;
        }
      } catch (err) {
        console.warn('[Auth] Redirect error:', err.message);
      }

      if (cancelled) return;

      const account = instance.getActiveAccount() || instance.getAllAccounts()[0];
      if (account) {
        instance.setActiveAccount(account);
        const role = await resolveRole(account);
        if (cancelled) return;
        setUserRole(role);
        setSessionUser(buildUser(account, role));
        setAuthState('active');
      } else {
        setAuthState('unauthenticated');
      }
    }

    init();
    return () => { cancelled = true; };
  }, [instance]);

  // ─── Acquire a fresh access token for Management API calls ──────────────
  const getAccessToken = useCallback(async () => {
    const account = instance.getActiveAccount() || instance.getAllAccounts()[0];
    if (!account) return null;
    try {
      const result = await instance.acquireTokenSilent({ scopes: [MGMT_SCOPE], account });
      return result?.accessToken ?? null;
    } catch (err) {
      console.warn('[Auth] Silent token failed, redirecting to login:', err.message);
      instance.loginRedirect({ scopes: [MGMT_SCOPE] });
      return null;
    }
  }, [instance]);

  // ─── Actions ─────────────────────────────────────────────────────────────
  const signIn = useCallback(() => {
    setAuthState('authenticating');
    instance.loginRedirect(loginRequest).catch(err => {
      console.error('[Auth] Login redirect error:', err);
      setAuthState('unauthenticated');
    });
  }, [instance]);

  const signOut = useCallback(() => {
    setSessionUser(null);
    setUserRole(null);
    setAuthState('unauthenticated');
    instance.logoutRedirect({ postLogoutRedirectUri: window.location.origin });
  }, [instance]);

  const retrySignIn = useCallback(() => {
    setAuthState('unauthenticated');
    instance.logoutRedirect({ postLogoutRedirectUri: window.location.origin }).catch(() => {
      setAuthState('unauthenticated');
    });
  }, [instance]);

  const value = {
    authState,
    sessionUser,
    userRole,                          // 'Admin' | 'Tech' | null
    isAdmin:         userRole === 'Admin',
    isTech:          userRole === 'Tech',
    isStaff:         userRole !== null,
    isAuthenticated: authState === 'active',
    getAccessToken,
    getIdToken: getAccessToken,        // alias — AdminContext still uses this name
    signIn,
    signOut,
    retrySignIn,
  };

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

// ─── Outer wrapper ────────────────────────────────────────────────────────────
export default function AuthProvider({ children }) {
  return (
    <MsalProvider instance={msalInstance}>
      <AuthInner>{children}</AuthInner>
    </MsalProvider>
  );
}

export { AuthProvider };
