"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useOxy = exports.default = exports.OxyProvider = exports.OxyContextProvider = void 0;
var _react = require("react");
var _core = require("../../core");
var _sessionUtils = require("../../utils/sessionUtils");
var _deviceManager = require("../../utils/deviceManager");
var _useSessionSocket = require("../hooks/useSessionSocket");
var _sonner = require("../../lib/sonner");
var _authStore = require("../stores/authStore");
var _languageUtils = require("../../utils/languageUtils");
var _jsxRuntime = require("react/jsx-runtime");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } // Define the context shape
// Create the context with default values
const OxyContext = /*#__PURE__*/(0, _react.createContext)(null);

// Props for the OxyContextProvider

// Platform storage implementation

// Web localStorage implementation
class WebStorage {
  async getItem(key) {
    return localStorage.getItem(key);
  }
  async setItem(key, value) {
    localStorage.setItem(key, value);
  }
  async removeItem(key) {
    localStorage.removeItem(key);
  }
  async clear() {
    localStorage.clear();
  }
}

// React Native AsyncStorage implementation
let AsyncStorage;

// Determine the platform and set up storage
const isReactNative = () => {
  return typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
};

// Get appropriate storage for the platform
const getStorage = async () => {
  if (isReactNative()) {
    if (!AsyncStorage) {
      try {
        const asyncStorageModule = await Promise.resolve().then(() => _interopRequireWildcard(require('@react-native-async-storage/async-storage')));
        AsyncStorage = asyncStorageModule.default;
      } catch (error) {
        console.error('Failed to import AsyncStorage:', error);
        throw new Error('AsyncStorage is required in React Native environment');
      }
    }
    return AsyncStorage;
  }
  return new WebStorage();
};

// Storage keys for sessions
const getStorageKeys = (prefix = 'oxy_session') => ({
  activeSessionId: `${prefix}_active_session_id`,
  // Only store the active session ID
  sessionIds: `${prefix}_session_ids`,
  // Store all session IDs for quick account loading
  language: `${prefix}_language` // Store the selected language
});
let cachedUseFollowHook = null;
const loadUseFollowHook = () => {
  if (cachedUseFollowHook) {
    return cachedUseFollowHook;
  }
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const {
      useFollow
    } = require('../hooks/useFollow');
    cachedUseFollowHook = useFollow;
    return cachedUseFollowHook;
  } catch (error) {
    if (__DEV__) {
      console.warn('useFollow hook is not available. Please import useFollow from @oxyhq/services directly.', error);
    }
    const fallback = () => {
      throw new Error('useFollow hook is only available in the UI bundle. Import it from @oxyhq/services.');
    };
    cachedUseFollowHook = fallback;
    return cachedUseFollowHook;
  }
};
const OxyProvider = ({
  children,
  oxyServices: providedOxyServices,
  baseURL,
  storageKeyPrefix = 'oxy_session',
  onAuthStateChange,
  onError,
  bottomSheetRef
}) => {
  // Create oxyServices automatically if not provided
  const oxyServicesRef = (0, _react.useRef)(null);
  if (!oxyServicesRef.current) {
    if (providedOxyServices) {
      oxyServicesRef.current = providedOxyServices;
    } else if (baseURL) {
      oxyServicesRef.current = new _core.OxyServices({
        baseURL
      });
    } else {
      throw new Error('Either oxyServices or baseURL must be provided to OxyContextProvider');
    }
  }
  const oxyServices = oxyServicesRef.current;

  // Zustand state
  const user = (0, _authStore.useAuthStore)(state => state.user);
  const isAuthenticated = (0, _authStore.useAuthStore)(state => state.isAuthenticated);
  const isLoading = (0, _authStore.useAuthStore)(state => state.isLoading);
  const error = (0, _authStore.useAuthStore)(state => state.error);
  const loginSuccess = (0, _authStore.useAuthStore)(state => state.loginSuccess);
  const loginFailure = (0, _authStore.useAuthStore)(state => state.loginFailure);
  const logoutStore = (0, _authStore.useAuthStore)(state => state.logout);

  // Local state for non-auth fields
  const [minimalUser, setMinimalUser] = (0, _react.useState)(null);
  const [sessions, setSessions] = (0, _react.useState)([]);
  const [activeSessionId, setActiveSessionId] = (0, _react.useState)(null);

  // Track in-flight refresh to prevent duplicate calls
  const refreshInFlightRef = (0, _react.useRef)(null);

  // Track recently removed session IDs to avoid validating them (cleared after 5 seconds)
  const removedSessionsRef = (0, _react.useRef)(new Set());
  const [storage, setStorage] = (0, _react.useState)(null);
  const [currentLanguage, setCurrentLanguage] = (0, _react.useState)('en-US');
  const useFollowHook = (0, _react.useMemo)(() => loadUseFollowHook(), []);

  // Storage keys (memoized to prevent infinite loops) - declared early for use in helpers
  const keys = (0, _react.useMemo)(() => getStorageKeys(storageKeyPrefix), [storageKeyPrefix]);

  // Helper to apply language preference from user/server
  const applyLanguagePreference = (0, _react.useCallback)(async user => {
    const userLanguage = user?.language;
    if (!userLanguage || !storage) return;
    try {
      const serverLang = (0, _languageUtils.normalizeLanguageCode)(userLanguage);
      await storage.setItem(keys.language, serverLang);
      setCurrentLanguage(serverLang);
    } catch (e) {
      if (__DEV__) {
        console.warn('Failed to apply server language preference', e);
      }
    }
  }, [storage, keys.language]);
  const mapSessionsToClient = (0, _react.useCallback)((sessions, fallbackDeviceId, fallbackUserId) => {
    return sessions.map(s => ({
      sessionId: s.sessionId,
      deviceId: s.deviceId || fallbackDeviceId || '',
      expiresAt: s.expiresAt || new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
      lastActive: s.lastActive || new Date().toISOString(),
      userId: s.user?.id || s.userId || s.user?._id?.toString() || fallbackUserId || '',
      isCurrent: Boolean(s.isCurrent)
    }));
  }, []);

  // Save all session IDs to storage for quick loading on initialization
  const saveSessionIds = (0, _react.useCallback)(async sessionIds => {
    if (!storage) return;
    try {
      const uniqueIds = Array.from(new Set(sessionIds));
      await storage.setItem(keys.sessionIds, JSON.stringify(uniqueIds));
    } catch (err) {
      if (__DEV__) {
        console.warn('Failed to save session IDs:', err);
      }
    }
  }, [storage, keys.sessionIds]);
  const updateSessions = (0, _react.useCallback)((newSessions, mergeWithExisting = false) => {
    setSessions(prevSessions => {
      const sessionsToProcess = mergeWithExisting ? (0, _sessionUtils.mergeSessions)(prevSessions, newSessions, activeSessionId, false) : (0, _sessionUtils.normalizeAndSortSessions)(newSessions, activeSessionId, false);

      // Save all session IDs to storage
      if (storage) {
        const allSessionIds = sessionsToProcess.map(s => s.sessionId);
        saveSessionIds(allSessionIds).catch(() => {
          // Ignore errors - non-critical
        });
      }
      return (0, _sessionUtils.sessionsArraysEqual)(prevSessions, sessionsToProcess) ? prevSessions : sessionsToProcess;
    });
  }, [activeSessionId, storage, saveSessionIds]);

  // Token ready state - start optimistically so children render immediately
  const [tokenReady, setTokenReady] = (0, _react.useState)(true);

  // Clear all storage
  const clearAllStorage = (0, _react.useCallback)(async () => {
    if (!storage) return;
    try {
      await storage.removeItem(keys.activeSessionId);
      await storage.removeItem(keys.sessionIds);
    } catch (err) {
      if (__DEV__) {
        console.error('Clear storage error:', err);
      }
      onError?.({
        message: 'Failed to clear storage',
        code: 'STORAGE_ERROR',
        status: 500
      });
    }
  }, [storage, keys, onError]);

  // Initialize storage
  (0, _react.useEffect)(() => {
    const initStorage = async () => {
      try {
        const platformStorage = await getStorage();
        setStorage(platformStorage);
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Failed to initialize storage';
        _authStore.useAuthStore.setState({
          error: errorMessage
        });
        onError?.({
          message: errorMessage,
          code: 'STORAGE_INIT_ERROR',
          status: 500
        });
      }
    };
    initStorage();
  }, [onError]);

  // Initialize authentication state
  // Note: We don't set isLoading during initialization to avoid showing spinners
  // Children render immediately and can check isTokenReady/isAuthenticated themselves
  (0, _react.useEffect)(() => {
    const initAuth = async () => {
      if (!storage) return;
      // Don't set isLoading during initialization - let it happen in background
      try {
        // Load saved language preference
        const savedLanguageRaw = await storage.getItem(keys.language);
        const savedLanguage = (0, _languageUtils.normalizeLanguageCode)(savedLanguageRaw) || savedLanguageRaw;
        if (savedLanguage) {
          setCurrentLanguage(savedLanguage);
        }

        // Load all stored session IDs and validate them
        const storedSessionIdsJson = await storage.getItem(keys.sessionIds);
        const storedSessionIds = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];

        // Try to restore active session from storage
        const storedActiveSessionId = await storage.getItem(keys.activeSessionId);
        const validSessions = [];

        // If we have stored session IDs, validate them (even without active session)
        if (storedSessionIds.length > 0) {
          if (__DEV__) {
            console.log('Loading stored sessions on init:', storedSessionIds.length);
          }

          // Validate each stored session ID and build session list
          for (const sessionId of storedSessionIds) {
            try {
              const validation = await oxyServices.validateSession(sessionId, {
                useHeaderValidation: true
              });
              if (validation.valid && validation.user) {
                validSessions.push({
                  sessionId,
                  userId: validation.user.id?.toString() || '',
                  deviceId: '',
                  expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),
                  lastActive: new Date().toISOString(),
                  isCurrent: sessionId === storedActiveSessionId
                });
              }
            } catch (e) {
              // Session invalid, skip it
              if (__DEV__) {
                console.warn('Session validation failed for:', sessionId, e);
              }
            }
          }

          // Update sessions list with validated sessions (even if no active session)
          if (validSessions.length > 0) {
            updateSessions(validSessions, false);
          }
        }

        // If we have an active session, authenticate with it
        if (storedActiveSessionId) {
          try {
            const validation = await oxyServices.validateSession(storedActiveSessionId, {
              useHeaderValidation: true
            });
            if (validation.valid) {
              setActiveSessionId(storedActiveSessionId);
              await oxyServices.getTokenBySession(storedActiveSessionId);
              const fullUser = await oxyServices.getUserBySession(storedActiveSessionId);
              loginSuccess(fullUser);
              setMinimalUser({
                id: fullUser.id,
                username: fullUser.username,
                avatar: fullUser.avatar
              });
              await applyLanguagePreference(fullUser);
              try {
                const deviceSessions = await oxyServices.getDeviceSessions(storedActiveSessionId);
                const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
                updateSessions(allDeviceSessions, true);
              } catch (e) {
                if (__DEV__) {
                  console.warn('Failed to get device sessions on init, falling back to user sessions:', e);
                }
                const serverSessions = await oxyServices.getSessionsBySessionId(storedActiveSessionId);
                updateSessions(mapSessionsToClient(serverSessions, undefined, fullUser.id), false);
              }
              onAuthStateChange?.(fullUser);
            } else {
              // Active session invalid, remove it but keep other sessions
              await storage.removeItem(keys.activeSessionId);
              // Update session list to remove invalid active session
              updateSessions(validSessions.filter(s => s.sessionId !== storedActiveSessionId), false);
            }
          } catch (e) {
            if (__DEV__) {
              console.error('Active session validation error', e);
            }
            // Remove invalid active session but keep other sessions
            await storage.removeItem(keys.activeSessionId);
            updateSessions(validSessions.filter(s => s.sessionId !== storedActiveSessionId), false);
          }
        }
        setTokenReady(true);
      } catch (e) {
        if (__DEV__) {
          console.error('Auth init error', e);
        }
        await clearAllStorage();
        setTokenReady(true);
      }
    };
    initAuth();
  }, [storage, oxyServices, keys, onAuthStateChange, loginSuccess, clearAllStorage, applyLanguagePreference, mapSessionsToClient, updateSessions]);

  // Save active session ID to storage (only session ID, no user data)
  const saveActiveSessionId = (0, _react.useCallback)(async sessionId => {
    if (!storage) return;
    await storage.setItem(keys.activeSessionId, sessionId);
  }, [storage, keys.activeSessionId]);
  const switchToSession = (0, _react.useCallback)(async sessionId => {
    try {
      const validation = await oxyServices.validateSession(sessionId, {
        useHeaderValidation: true
      });
      if (!validation.valid) {
        updateSessions(sessions.filter(s => s.sessionId !== sessionId), false);
        throw new Error('Session is invalid or expired');
      }
      if (!validation.user) {
        throw new Error('User data not available from session validation');
      }
      const fullUser = validation.user;
      await oxyServices.getTokenBySession(sessionId);
      setTokenReady(true);
      setActiveSessionId(sessionId);
      loginSuccess(fullUser);
      setMinimalUser({
        id: fullUser.id,
        username: fullUser.username,
        avatar: fullUser.avatar
      });
      await saveActiveSessionId(sessionId);
      await applyLanguagePreference(fullUser);
      oxyServices.getDeviceSessions(sessionId).then(deviceSessions => {
        const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
        updateSessions(allDeviceSessions, true);
      }).catch(error => {
        if (__DEV__) console.warn('Failed to get device sessions after switch:', error);
      });
      onAuthStateChange?.(fullUser);
    } catch (error) {
      const isInvalidSession = error?.response?.status === 401 || error?.message?.includes('Invalid or expired session') || error?.message?.includes('Session is invalid');
      if (isInvalidSession) {
        updateSessions(sessions.filter(s => s.sessionId !== sessionId), false);
        if (sessionId === activeSessionId && sessions.length > 1) {
          const otherSessions = sessions.filter(s => s.sessionId !== sessionId);
          for (const otherSession of otherSessions) {
            try {
              const otherValidation = await oxyServices.validateSession(otherSession.sessionId, {
                useHeaderValidation: true
              });
              if (otherValidation.valid) {
                await switchToSession(otherSession.sessionId);
                return;
              }
            } catch {
              // Continue to next session
              continue;
            }
          }
        }
      }
      const errorMessage = error instanceof Error ? error.message : 'Failed to switch session';
      if (__DEV__) {
        console.error('Switch session error:', error);
      }
      _authStore.useAuthStore.setState({
        error: errorMessage
      });
      onError?.({
        message: errorMessage,
        code: isInvalidSession ? 'INVALID_SESSION' : 'SESSION_SWITCH_ERROR',
        status: isInvalidSession ? 401 : 500
      });
      setTokenReady(false);
      throw error; // Re-throw so calling code can handle it
    }
  }, [oxyServices, onAuthStateChange, loginSuccess, saveActiveSessionId, applyLanguagePreference, mapSessionsToClient, onError, activeSessionId, sessions]);
  const login = (0, _react.useCallback)(async (username, password, deviceName) => {
    if (!storage) throw new Error('Storage not initialized');
    _authStore.useAuthStore.setState({
      isLoading: true,
      error: null
    });
    try {
      const deviceFingerprint = _deviceManager.DeviceManager.getDeviceFingerprint();
      const deviceInfo = await _deviceManager.DeviceManager.getDeviceInfo();
      const response = await oxyServices.signIn(username, password, deviceName || deviceInfo.deviceName || _deviceManager.DeviceManager.getDefaultDeviceName(), deviceFingerprint);

      // Handle MFA requirement
      if (response && 'mfaRequired' in response && response.mfaRequired) {
        const mfaError = new Error('Multi-factor authentication required');
        mfaError.code = 'MFA_REQUIRED';
        mfaError.mfaToken = response.mfaToken;
        mfaError.expiresAt = response.expiresAt;
        throw mfaError;
      }
      const sessionResponse = response;
      await oxyServices.getTokenBySession(sessionResponse.sessionId);
      const fullUser = await oxyServices.getUserBySession(sessionResponse.sessionId);
      let allDeviceSessions = [];
      try {
        const deviceSessions = await oxyServices.getDeviceSessions(sessionResponse.sessionId);
        allDeviceSessions = mapSessionsToClient(deviceSessions, sessionResponse.deviceId, fullUser.id);
      } catch (error) {
        if (__DEV__) {
          console.warn('Failed to get device sessions, falling back to user sessions:', error);
        }
        const serverSessions = await oxyServices.getSessionsBySessionId(sessionResponse.sessionId);
        allDeviceSessions = mapSessionsToClient(serverSessions, undefined, fullUser.id);
      }
      const userUserId = fullUser.id?.toString();
      const existingSession = allDeviceSessions.find(s => s.userId?.toString() === userUserId && s.sessionId !== sessionResponse.sessionId);
      if (existingSession) {
        try {
          await oxyServices.logoutSession(sessionResponse.sessionId, sessionResponse.sessionId);
        } catch (logoutError) {
          if (__DEV__) {
            console.warn('Failed to logout duplicate session:', logoutError);
          }
        }
        await switchToSession(existingSession.sessionId);
        loginSuccess(fullUser);
        setMinimalUser(sessionResponse.user);
        updateSessions(allDeviceSessions.filter(s => s.sessionId !== sessionResponse.sessionId), false);
        onAuthStateChange?.(fullUser);
        return fullUser;
      }
      setActiveSessionId(sessionResponse.sessionId);
      await saveActiveSessionId(sessionResponse.sessionId);
      loginSuccess(fullUser);
      setMinimalUser(sessionResponse.user);
      updateSessions(allDeviceSessions, true);
      onAuthStateChange?.(fullUser);
      return fullUser;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Login failed';
      loginFailure(errorMessage);
      onError?.({
        message: errorMessage,
        code: 'LOGIN_ERROR',
        status: 401
      });
      throw error;
    } finally {
      _authStore.useAuthStore.setState({
        isLoading: false
      });
    }
  }, [storage, oxyServices, saveActiveSessionId, loginSuccess, onAuthStateChange, loginFailure, mapSessionsToClient, onError, sessions, switchToSession]);

  // Clear session state without calling API (for remote removals)
  const clearSessionState = (0, _react.useCallback)(async () => {
    updateSessions([], false);
    setActiveSessionId(null);
    logoutStore();
    setMinimalUser(null);
    await clearAllStorage();
    onAuthStateChange?.(null);
  }, [updateSessions, logoutStore, clearAllStorage, onAuthStateChange]);

  // Logout method
  const logout = (0, _react.useCallback)(async targetSessionId => {
    if (!activeSessionId) return;
    try {
      const sessionToLogout = targetSessionId || activeSessionId;
      await oxyServices.logoutSession(activeSessionId, sessionToLogout);
      const filteredSessions = sessions.filter(s => s.sessionId !== sessionToLogout);
      updateSessions(filteredSessions, false);
      if (sessionToLogout === activeSessionId) {
        if (filteredSessions.length > 0) {
          await switchToSession(filteredSessions[0].sessionId);
        } else {
          setActiveSessionId(null);
          logoutStore();
          setMinimalUser(null);
          await storage?.removeItem(keys.activeSessionId);
          if (onAuthStateChange) {
            onAuthStateChange(null);
          }
        }
      }
    } catch (error) {
      // Check if error is 401 (session already removed remotely)
      const is401Error = error?.response?.status === 401 || error?.message?.includes('Invalid or expired session') || error?.message?.includes('Session is invalid');
      if (is401Error && targetSessionId === activeSessionId) {
        // Session was already removed remotely, clear state without API call
        await clearSessionState();
        return;
      }
      const errorMessage = error instanceof Error ? error.message : 'Logout failed';
      if (__DEV__) {
        console.error('Logout error:', error);
      }
      _authStore.useAuthStore.setState({
        error: errorMessage
      });
      onError?.({
        message: errorMessage,
        code: 'LOGOUT_ERROR',
        status: 500
      });
    }
  }, [activeSessionId, oxyServices, sessions, switchToSession, logoutStore, storage, keys.activeSessionId, onAuthStateChange, onError, clearSessionState]);
  const logoutAll = (0, _react.useCallback)(async () => {
    if (!activeSessionId) {
      const error = new Error('No active session found');
      _authStore.useAuthStore.setState({
        error: error.message
      });
      onError?.({
        message: error.message,
        code: 'NO_SESSION_ERROR',
        status: 404
      });
      throw error;
    }
    try {
      await oxyServices.logoutAllSessions(activeSessionId);
      updateSessions([], false);
      setActiveSessionId(null);
      logoutStore();
      setMinimalUser(null);
      await clearAllStorage();
      onAuthStateChange?.(null);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Logout all failed';
      _authStore.useAuthStore.setState({
        error: errorMessage
      });
      onError?.({
        message: errorMessage,
        code: 'LOGOUT_ALL_ERROR',
        status: 500
      });
      throw error;
    }
  }, [activeSessionId, oxyServices, logoutStore, clearAllStorage, onAuthStateChange, onError]);

  // Token restoration is handled in initAuth and switchToSession
  // No separate effect needed - children render immediately with isTokenReady available

  // Sign up method
  const signUp = (0, _react.useCallback)(async (username, email, password) => {
    if (!storage) throw new Error('Storage not initialized');
    _authStore.useAuthStore.setState({
      isLoading: true,
      error: null
    });
    try {
      await oxyServices.signUp(username, email, password);
      const user = await login(username, password);
      return user;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Sign up failed';
      loginFailure(errorMessage);
      onError?.({
        message: errorMessage,
        code: 'SIGNUP_ERROR',
        status: 400
      });
      throw error;
    } finally {
      _authStore.useAuthStore.setState({
        isLoading: false
      });
    }
  }, [storage, oxyServices, login, loginFailure, onError]);

  // Complete MFA login by verifying TOTP
  const completeMfaLogin = (0, _react.useCallback)(async (mfaToken, code) => {
    if (!storage) throw new Error('Storage not initialized');
    _authStore.useAuthStore.setState({
      isLoading: true,
      error: null
    });
    try {
      const response = await oxyServices.verifyTotpLogin(mfaToken, code);

      // Set as active session
      setActiveSessionId(response.sessionId);
      await saveActiveSessionId(response.sessionId);

      // Fetch access token and user data
      await oxyServices.getTokenBySession(response.sessionId);
      const fullUser = await oxyServices.getUserBySession(response.sessionId);
      loginSuccess(fullUser);
      setMinimalUser({
        id: fullUser.id,
        username: fullUser.username,
        avatar: fullUser.avatar
      });
      await applyLanguagePreference(fullUser);

      // Get all device sessions to support multiple accounts
      try {
        const deviceSessions = await oxyServices.getDeviceSessions(response.sessionId);
        const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, fullUser.id);
        updateSessions(allDeviceSessions, true);
      } catch (error) {
        // Fallback to user sessions if device sessions fail
        if (__DEV__) {
          console.warn('Failed to get device sessions for MFA, falling back to user sessions:', error);
        }
        const serverSessions = await oxyServices.getSessionsBySessionId(response.sessionId);
        const userSessions = mapSessionsToClient(serverSessions, undefined, fullUser.id);
        updateSessions(userSessions, true);
      }
      onAuthStateChange?.(fullUser);
      return fullUser;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'MFA verification failed';
      loginFailure(errorMessage);
      onError?.({
        message: errorMessage,
        code: 'MFA_ERROR',
        status: 401
      });
      throw error;
    } finally {
      _authStore.useAuthStore.setState({
        isLoading: false
      });
    }
  }, [storage, oxyServices, loginSuccess, loginFailure, saveActiveSessionId, onAuthStateChange, applyLanguagePreference, onError]);
  const switchSession = (0, _react.useCallback)(async sessionId => {
    await switchToSession(sessionId);
  }, [switchToSession]);
  const removeSession = (0, _react.useCallback)(async sessionId => {
    await logout(sessionId);
  }, [logout]);
  const refreshSessions = (0, _react.useCallback)(async () => {
    if (!activeSessionId) return;

    // If a refresh is already in progress, return the existing promise
    if (refreshInFlightRef.current) {
      return refreshInFlightRef.current;
    }

    // Create the refresh promise
    const refreshPromise = (async () => {
      try {
        const deviceSessions = await oxyServices.getDeviceSessions(activeSessionId);
        const allDeviceSessions = mapSessionsToClient(deviceSessions, undefined, user?.id);
        updateSessions(allDeviceSessions, true);
      } catch (error) {
        if (__DEV__) {
          console.warn('Failed to refresh device sessions, falling back to user sessions:', error);
        }
        try {
          const serverSessions = await oxyServices.getSessionsBySessionId(activeSessionId);
          const userSessions = mapSessionsToClient(serverSessions, undefined, user?.id);
          updateSessions(userSessions, true);
        } catch (fallbackError) {
          if (__DEV__) {
            console.error('Refresh sessions error:', fallbackError);
          }

          // Check if the error is a 401 (session removed/invalid)
          const is401Error = fallbackError?.response?.status === 401 || fallbackError?.message?.includes('Invalid or expired session') || fallbackError?.message?.includes('Session is invalid');

          // If 401 error, don't try to validate other sessions - they may have been removed too
          // Instead, check if current session is in removed sessions list
          if (is401Error && removedSessionsRef.current.has(activeSessionId || '')) {
            // Current session was removed, clear all and logout
            updateSessions([], false);
            setActiveSessionId(null);
            logoutStore();
            setMinimalUser(null);
            await clearAllStorage();
            onAuthStateChange?.(null);
            return;
          }

          // If the current session is invalid, try to find another valid session
          // But skip sessions that were recently removed
          if (sessions.length > 1) {
            const otherSessions = sessions.filter(s => s.sessionId !== activeSessionId && !removedSessionsRef.current.has(s.sessionId));
            for (const session of otherSessions) {
              try {
                const validation = await oxyServices.validateSession(session.sessionId, {
                  useHeaderValidation: true
                });
                if (validation.valid) {
                  await switchToSession(session.sessionId);
                  return;
                }
              } catch (validationError) {
                // If validation returns 401, mark this session as removed
                const isValidation401 = validationError?.response?.status === 401 || validationError?.message?.includes('Invalid or expired session');
                if (isValidation401) {
                  removedSessionsRef.current.add(session.sessionId);
                  // Clear from tracking after 5 seconds
                  setTimeout(() => {
                    removedSessionsRef.current.delete(session.sessionId);
                  }, 5000);
                }
                continue;
              }
            }
          }

          // No valid sessions found, clear all
          updateSessions([], false);
          setActiveSessionId(null);
          logoutStore();
          setMinimalUser(null);
          await clearAllStorage();
          onAuthStateChange?.(null);
        }
      } finally {
        // Clear the in-flight ref when done
        refreshInFlightRef.current = null;
      }
    })();
    refreshInFlightRef.current = refreshPromise;
    return refreshPromise;
  }, [activeSessionId, oxyServices, user?.id, updateSessions, sessions, switchToSession, logoutStore, clearAllStorage, onAuthStateChange, mapSessionsToClient]);

  // Device management methods
  const getDeviceSessions = (0, _react.useCallback)(async () => {
    if (!activeSessionId) throw new Error('No active session');
    try {
      return await oxyServices.getDeviceSessions(activeSessionId);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Failed to get device sessions';
      onError?.({
        message: errorMessage,
        code: 'GET_DEVICE_SESSIONS_ERROR',
        status: 500
      });
      throw error;
    }
  }, [activeSessionId, oxyServices, onError]);
  const logoutAllDeviceSessions = (0, _react.useCallback)(async () => {
    if (!activeSessionId) throw new Error('No active session');
    try {
      await oxyServices.logoutAllDeviceSessions(activeSessionId);
      updateSessions([], false);
      setActiveSessionId(null);
      logoutStore();
      setMinimalUser(null);
      await clearAllStorage();
      onAuthStateChange?.(null);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Failed to logout all device sessions';
      onError?.({
        message: errorMessage,
        code: 'LOGOUT_ALL_DEVICES_ERROR',
        status: 500
      });
      throw error;
    }
  }, [activeSessionId, oxyServices, logoutStore, clearAllStorage, onAuthStateChange, onError]);
  const updateDeviceName = (0, _react.useCallback)(async deviceName => {
    if (!activeSessionId) throw new Error('No active session');
    try {
      await oxyServices.updateDeviceName(activeSessionId, deviceName);
      await _deviceManager.DeviceManager.updateDeviceName(deviceName);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Failed to update device name';
      onError?.({
        message: errorMessage,
        code: 'UPDATE_DEVICE_NAME_ERROR',
        status: 500
      });
      throw error;
    }
  }, [activeSessionId, oxyServices, onError]);

  // Language management method
  const setLanguage = (0, _react.useCallback)(async languageId => {
    if (!storage) throw new Error('Storage not initialized');
    try {
      await storage.setItem(keys.language, languageId);
      setCurrentLanguage(languageId);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Failed to save language preference';
      onError?.({
        message: errorMessage,
        code: 'LANGUAGE_SAVE_ERROR',
        status: 500
      });
      throw error;
    }
  }, [storage, keys.language, onError]);

  // Bottom sheet control methods
  const showBottomSheet = (0, _react.useCallback)(screenOrConfig => {
    if (__DEV__) console.log('showBottomSheet called with:', screenOrConfig);
    if (bottomSheetRef?.current) {
      if (__DEV__) console.log('bottomSheetRef is available');

      // First, show the bottom sheet
      if (bottomSheetRef.current.expand) {
        if (__DEV__) console.log('Expanding bottom sheet');
        bottomSheetRef.current.expand();
      } else if (bottomSheetRef.current.present) {
        if (__DEV__) console.log('Presenting bottom sheet');
        bottomSheetRef.current.present();
      } else if (__DEV__) {
        console.warn('No expand or present method available on bottomSheetRef');
      }

      // Then navigate to the specified screen if provided
      if (screenOrConfig) {
        // Add a small delay to ensure the bottom sheet is opened first
        setTimeout(() => {
          if (typeof screenOrConfig === 'string') {
            // Simple screen name
            if (__DEV__) console.log('Navigating to screen:', screenOrConfig);
            bottomSheetRef.current?.navigate?.(screenOrConfig);
          } else {
            // Screen with props
            if (__DEV__) console.log('Navigating to screen with props:', screenOrConfig.screen, screenOrConfig.props);
            bottomSheetRef.current?.navigate?.(screenOrConfig.screen, screenOrConfig.props);
          }
        }, 100);
      }
    } else if (__DEV__) {
      console.warn('bottomSheetRef is not available. Pass a bottomSheetRef to OxyProvider.');
    }
  }, [bottomSheetRef]);
  const hideBottomSheet = (0, _react.useCallback)(() => {
    if (bottomSheetRef?.current) {
      bottomSheetRef.current.dismiss?.();
    }
  }, [bottomSheetRef]);

  // Get current deviceId from active session
  const currentDeviceId = (0, _react.useMemo)(() => {
    if (!activeSessionId || !sessions.length) return null;
    const activeSession = sessions.find(s => s.sessionId === activeSessionId);
    return activeSession?.deviceId || null;
  }, [activeSessionId, sessions]);

  // Callback to track removed sessions
  const handleSessionRemoved = (0, _react.useCallback)(sessionId => {
    // Add to removed sessions tracking
    removedSessionsRef.current.add(sessionId);
    // Clear from tracking after 5 seconds
    setTimeout(() => {
      removedSessionsRef.current.delete(sessionId);
    }, 5000);
  }, []);

  // Integrate socket for real-time session updates
  (0, _useSessionSocket.useSessionSocket)({
    userId: user?.id,
    activeSessionId,
    currentDeviceId,
    refreshSessions,
    logout,
    clearSessionState,
    baseURL: oxyServices.getBaseURL(),
    onRemoteSignOut: (0, _react.useCallback)(() => {
      _sonner.toast.info('You have been signed out remotely.');
      logout();
    }, [logout]),
    onSessionRemoved: handleSessionRemoved
  });

  // Compute language metadata from currentLanguage
  const languageMetadata = (0, _react.useMemo)(() => (0, _languageUtils.getLanguageMetadata)(currentLanguage), [currentLanguage]);
  const languageName = (0, _react.useMemo)(() => (0, _languageUtils.getLanguageName)(currentLanguage), [currentLanguage]);
  const nativeLanguageName = (0, _react.useMemo)(() => (0, _languageUtils.getNativeLanguageName)(currentLanguage), [currentLanguage]);
  const contextValue = (0, _react.useMemo)(() => ({
    user,
    minimalUser,
    sessions,
    activeSessionId,
    isAuthenticated,
    isLoading,
    isTokenReady: tokenReady,
    error,
    currentLanguage,
    currentLanguageMetadata: languageMetadata,
    currentLanguageName: languageName,
    currentNativeLanguageName: nativeLanguageName,
    login,
    logout,
    logoutAll,
    signUp,
    completeMfaLogin,
    switchSession,
    removeSession,
    refreshSessions,
    setLanguage,
    getDeviceSessions,
    logoutAllDeviceSessions,
    updateDeviceName,
    oxyServices,
    bottomSheetRef,
    showBottomSheet,
    hideBottomSheet,
    useFollow: useFollowHook
  }), [user?.id,
  // Only depend on user ID, not the entire user object
  minimalUser?.id, sessions.length,
  // Only depend on sessions count, not the entire array
  activeSessionId, isAuthenticated, isLoading, tokenReady, error, currentLanguage, languageMetadata, languageName, nativeLanguageName, login, logout, logoutAll, signUp, completeMfaLogin, switchSession, removeSession, refreshSessions, setLanguage, getDeviceSessions, logoutAllDeviceSessions, updateDeviceName, oxyServices, bottomSheetRef, showBottomSheet, hideBottomSheet, useFollowHook]);

  // Always render children - let the consuming app decide how to handle token loading state
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(OxyContext.Provider, {
    value: contextValue,
    children: children
  });
};

// Alias for backward compatibility
exports.OxyProvider = OxyProvider;
const OxyContextProvider = exports.OxyContextProvider = OxyProvider;

// Hook to use the context
const useOxy = () => {
  const context = (0, _react.useContext)(OxyContext);
  if (!context) {
    throw new Error('useOxy must be used within an OxyContextProvider');
  }
  return context;
};
exports.useOxy = useOxy;
var _default = exports.default = OxyContext;
//# sourceMappingURL=OxyContext.js.map