import { createContext, useContext, useReducer, useEffect } from 'react';
import * as db from '../lib/db';
import { pb } from '../lib/pb';
import { OIDC_PROVIDER } from '../lib/azureAuth';
import { getPersonalWeekNumber } from '../lib/curriculumService';

const AppContext = createContext();

const initialState = {
  currentUser: null,
  users: [],
  weekNumber: 0,
  isLoading: true
};

function computeWeekNumber(user) {
  if (!user || !user.curriculum_started_at || user.enrollment_status !== 'active') return 0;
  return getPersonalWeekNumber(user.curriculum_started_at);
}

function appReducer(state, action) {
  switch (action.type) {
    case 'INIT_APP':
      return {
        ...state,
        users: action.payload.users,
        isLoading: false
      };
    case 'LOGIN':
      return {
        ...state,
        currentUser: action.payload,
        weekNumber: computeWeekNumber(action.payload),
      };
    case 'UPDATE_CURRENT_USER':
      return {
        ...state,
        currentUser: action.payload,
        weekNumber: computeWeekNumber(action.payload),
        users: state.users.map(u => u.id === action.payload.id ? action.payload : u),
      };
    case 'LOGOUT':
      return { ...state, currentUser: null, weekNumber: 0 };
    default:
      return state;
  }
}

export function AppProvider({ children }) {
  const [state, dispatch] = useReducer(appReducer, initialState);

  useEffect(() => {
    const loadState = async () => {
      // Restore the session from PocketBase's persistent auth store. The token
      // is kept in localStorage by the SDK; authRefresh verifies it is still
      // valid (and that the Entra account hasn't been revoked) and returns the
      // up-to-date record.
      if (pb.authStore.isValid && pb.authStore.record?.collectionName === 'team_members') {
        try {
          const { record } = await pb.collection('team_members').authRefresh();
          dispatch({ type: 'LOGIN', payload: record });
        } catch {
          // Token rejected (expired / account revoked) — drop the session.
          pb.authStore.clear();
        }
      }

      // The team list (leaderboard, dashboard) requires authentication now, so
      // only load it once we have a valid session.
      const members = pb.authStore.isValid ? await db.getTeamMembers() : [];
      dispatch({ type: 'INIT_APP', payload: { users: members } });
    };

    loadState().catch(console.error);
  }, []);

  // Start the Entra (OIDC) login flow. PocketBase opens the provider popup,
  // handles the token exchange server-side, and auto-provisions the record on
  // first login (see pb_hooks/team_members.pb.js).
  const loginWithAzure = async () => {
    const authData = await pb.collection('team_members').authWithOAuth2({ provider: OIDC_PROVIDER });
    dispatch({ type: 'LOGIN', payload: authData.record });
    return authData.record;
  };

  const logout = () => {
    pb.authStore.clear();
    dispatch({ type: 'LOGOUT' });
  };

  /**
   * Start the curriculum for the currently logged-in user.
   * Records the start timestamp and flips enrollment_status to 'active'.
   */
  const enrollCurrentUser = async () => {
    if (!state.currentUser) throw new Error('No user is logged in.');
    const startedAt = new Date().toISOString();
    const updated = await pb.collection('team_members').update(state.currentUser.id, {
      curriculum_started_at: startedAt,
      enrollment_status: 'active',
    });
    dispatch({ type: 'UPDATE_CURRENT_USER', payload: updated });
    return updated;
  };

  return (
    <AppContext.Provider value={{ state, dispatch, loginWithAzure, logout, enrollCurrentUser }}>
      {children}
    </AppContext.Provider>
  );
}

export function useApp() {
  return useContext(AppContext);
}
