"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 _sonner = require("../../lib/sonner");
var _authStore = require("../stores/authStore");
var _shallow = require("zustand/react/shallow");
var _useSessionSocket = require("../hooks/useSessionSocket");
var _useStorage = require("../hooks/useStorage");
var _useLanguageManagement = require("../hooks/useLanguageManagement");
var _useSessionManagement = require("../hooks/useSessionManagement");
var _useAuthOperations = require("./hooks/useAuthOperations");
var _useDeviceManagement = require("../hooks/useDeviceManagement");
var _storageHelpers = require("../utils/storageHelpers");
var _errorHandlers = require("../utils/errorHandlers");
var _bottomSheetManager = require("../navigation/bottomSheetManager");
var _reactQuery = require("@tanstack/react-query");
var _queryClient = require("../hooks/queryClient");
var _accountStore = require("../stores/accountStore");
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); }
const OxyContext = /*#__PURE__*/(0, _react.createContext)(null);
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
}) => {
  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;
  const {
    user,
    isAuthenticated,
    isLoading,
    error,
    loginSuccess,
    loginFailure,
    logoutStore,
    // Identity sync state and actions
    isIdentitySyncedStore,
    isSyncing,
    setIdentitySynced,
    setSyncing
  } = (0, _authStore.useAuthStore)((0, _shallow.useShallow)(state => ({
    user: state.user,
    isAuthenticated: state.isAuthenticated,
    isLoading: state.isLoading,
    error: state.error,
    loginSuccess: state.loginSuccess,
    loginFailure: state.loginFailure,
    logoutStore: state.logout,
    // Identity sync state and actions
    isIdentitySyncedStore: state.isIdentitySynced,
    isSyncing: state.isSyncing,
    setIdentitySynced: state.setIdentitySynced,
    setSyncing: state.setSyncing
  })));
  const [tokenReady, setTokenReady] = (0, _react.useState)(true);
  const initializedRef = (0, _react.useRef)(false);
  const setAuthState = _authStore.useAuthStore.setState;
  const logger = (0, _react.useCallback)((message, err) => {
    if (__DEV__) {
      console.warn(`[OxyContext] ${message}`, err);
    }
  }, []);
  const storageKeys = (0, _react.useMemo)(() => (0, _storageHelpers.getStorageKeys)(storageKeyPrefix), [storageKeyPrefix]);
  const {
    storage,
    isReady: isStorageReady
  } = (0, _useStorage.useStorage)({
    onError,
    logger
  });

  // Identity integrity check and auto-restore on startup
  (0, _react.useEffect)(() => {
    if (!storage || !isStorageReady) return;
    const checkAndRestoreIdentity = async () => {
      try {
        const {
          KeyManager
        } = await Promise.resolve().then(() => _interopRequireWildcard(require('../../crypto/index.js')));
        // Check if identity exists and verify integrity
        const hasIdentity = await KeyManager.hasIdentity();
        if (hasIdentity) {
          const isValid = await KeyManager.verifyIdentityIntegrity();
          if (!isValid) {
            // Try to restore from backup
            const restored = await KeyManager.restoreIdentityFromBackup();
            if (restored) {
              if (__DEV__) {
                logger('Identity restored from backup successfully');
              }
            } else {
              if (__DEV__) {
                logger('Identity integrity check failed - user may need to restore from recovery phrase');
              }
            }
          } else {
            // Identity is valid - ensure backup is up to date
            await KeyManager.backupIdentity();
          }
        } else {
          // No identity - try to restore from backup
          const restored = await KeyManager.restoreIdentityFromBackup();
          if (restored && __DEV__) {
            logger('Identity restored from backup on startup');
          }
        }
      } catch (error) {
        if (__DEV__) {
          logger('Error during identity integrity check', error);
        }
        // Don't block app startup - user can recover with recovery phrase
      }
    };
    checkAndRestoreIdentity();
  }, [storage, isStorageReady, logger]);

  // Offline queuing is now handled by TanStack Query mutations
  // No need for custom offline queue

  const {
    currentLanguage,
    metadata: currentLanguageMetadata,
    languageName: currentLanguageName,
    nativeLanguageName: currentNativeLanguageName,
    setLanguage,
    applyLanguagePreference
  } = (0, _useLanguageManagement.useLanguageManagement)({
    storage,
    languageKey: storageKeys.language,
    onError,
    logger
  });
  const queryClient = (0, _reactQuery.useQueryClient)();
  const {
    sessions,
    activeSessionId,
    setActiveSessionId,
    updateSessions,
    switchSession,
    refreshSessions,
    clearSessionState,
    saveActiveSessionId,
    trackRemovedSession
  } = (0, _useSessionManagement.useSessionManagement)({
    oxyServices,
    storage,
    storageKeyPrefix,
    loginSuccess,
    logoutStore,
    applyLanguagePreference,
    onAuthStateChange,
    onError,
    setAuthError: message => setAuthState({
      error: message
    }),
    logger,
    setTokenReady,
    queryClient
  });
  const {
    createIdentity,
    importIdentity,
    signIn,
    logout,
    logoutAll,
    hasIdentity,
    getPublicKey,
    isIdentitySynced,
    syncIdentity: syncIdentityBase
  } = (0, _useAuthOperations.useAuthOperations)({
    oxyServices,
    storage,
    sessions,
    activeSessionId,
    setActiveSessionId,
    updateSessions,
    saveActiveSessionId,
    clearSessionState,
    switchSession,
    applyLanguagePreference,
    onAuthStateChange,
    onError,
    loginSuccess,
    loginFailure,
    logoutStore,
    setAuthState,
    setIdentitySynced,
    setSyncing,
    logger
  });

  // syncIdentity - TanStack Query handles offline mutations automatically
  const syncIdentity = (0, _react.useCallback)(async () => {
    return await syncIdentityBase();
  }, [syncIdentityBase]);

  // Clear all account data when identity is lost (for accounts app)
  // In accounts app, identity = account, so losing identity means losing everything
  const clearAllAccountData = (0, _react.useCallback)(async () => {
    // Clear TanStack Query cache (in-memory)
    queryClient.clear();

    // Clear persisted query cache
    if (storage) {
      try {
        await (0, _queryClient.clearQueryCache)(storage);
      } catch (error) {
        if (logger) {
          logger('Failed to clear persisted query cache', error);
        }
      }
    }

    // Clear session state (sessions, activeSessionId, storage)
    await clearSessionState();

    // Clear identity sync state from storage
    if (storage) {
      try {
        await storage.removeItem('oxy_identity_synced');
      } catch (error) {
        if (logger) {
          logger('Failed to clear identity sync state', error);
        }
      }
    }

    // Reset auth store identity sync state
    _authStore.useAuthStore.getState().setIdentitySynced(false);
    _authStore.useAuthStore.getState().setSyncing(false);

    // Reset account store
    _accountStore.useAccountStore.getState().reset();

    // Clear HTTP service cache
    oxyServices.clearCache();
  }, [queryClient, storage, clearSessionState, logger, oxyServices]);

  // Delete identity and clear all account data
  // In accounts app, deleting identity means losing the account completely
  const deleteIdentityAndClearAccount = (0, _react.useCallback)(async (skipBackup = false, force = false, userConfirmed = false) => {
    // First, clear all account data
    await clearAllAccountData();

    // Then delete the identity keys
    const {
      KeyManager
    } = await Promise.resolve().then(() => _interopRequireWildcard(require('../../crypto/keyManager.js')));
    await KeyManager.deleteIdentity(skipBackup, force, userConfirmed);
  }, [clearAllAccountData]);

  // Network reconnect sync - TanStack Query automatically retries mutations on reconnect
  // We only need to sync identity if it's not synced
  (0, _react.useEffect)(() => {
    if (!storage) return;
    let wasOffline = false;
    let checkInterval = null;
    const checkNetworkAndSync = async () => {
      try {
        // Try a lightweight health check to see if we're online
        await oxyServices.healthCheck().catch(() => {
          wasOffline = true;
          return;
        });

        // If we were offline and now we're online, sync identity if needed
        if (wasOffline) {
          if (__DEV__ && logger) {
            logger('Network reconnected, checking identity sync...');
          }

          // Sync identity first (if not synced)
          try {
            const isSynced = await storage.getItem('oxy_identity_synced');
            if (isSynced === 'false') {
              await syncIdentity();
            }
          } catch (syncError) {
            if (__DEV__ && logger) {
              logger('Error syncing identity on reconnect', syncError);
            }
          }

          // TanStack Query will automatically retry pending mutations
          wasOffline = false;
        }
      } catch (error) {
        // Network check failed - we're offline
        wasOffline = true;
      }
    };

    // Check immediately
    checkNetworkAndSync();

    // Check periodically (every 10 seconds when app is active)
    checkInterval = setInterval(checkNetworkAndSync, 10000);
    return () => {
      if (checkInterval) {
        clearInterval(checkInterval);
      }
    };
  }, [oxyServices, storage, syncIdentity, logger]);
  const {
    getDeviceSessions,
    logoutAllDeviceSessions,
    updateDeviceName
  } = (0, _useDeviceManagement.useDeviceManagement)({
    oxyServices,
    activeSessionId,
    onError,
    clearSessionState,
    logger
  });
  const useFollowHook = loadUseFollowHook();
  const restoreSessionsFromStorage = (0, _react.useCallback)(async () => {
    if (!storage) {
      return;
    }
    setTokenReady(false);
    try {
      const storedSessionIdsJson = await storage.getItem(storageKeys.sessionIds);
      const storedSessionIds = storedSessionIdsJson ? JSON.parse(storedSessionIdsJson) : [];
      const storedActiveSessionId = await storage.getItem(storageKeys.activeSessionId);
      const validSessions = [];
      if (storedSessionIds.length > 0) {
        for (const sessionId of storedSessionIds) {
          try {
            const validation = await oxyServices.validateSession(sessionId, {
              useHeaderValidation: true
            });
            if (validation?.valid && validation.user) {
              const now = new Date();
              validSessions.push({
                sessionId,
                deviceId: '',
                expiresAt: new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000).toISOString(),
                lastActive: now.toISOString(),
                userId: validation.user.id?.toString() ?? '',
                isCurrent: sessionId === storedActiveSessionId
              });
            }
          } catch (validationError) {
            logger('Session validation failed during init', validationError);
          }
        }
        if (validSessions.length > 0) {
          updateSessions(validSessions, {
            merge: false
          });
        }
      }
      if (storedActiveSessionId) {
        try {
          await switchSession(storedActiveSessionId);
        } catch (switchError) {
          if ((0, _errorHandlers.isInvalidSessionError)(switchError)) {
            await storage.removeItem(storageKeys.activeSessionId);
            updateSessions(validSessions.filter(session => session.sessionId !== storedActiveSessionId), {
              merge: false
            });
          } else {
            logger('Active session validation error', switchError);
          }
        }
      }
    } catch (error) {
      if (__DEV__) {
        console.error('Auth init error', error);
      }
      await clearSessionState();
    } finally {
      setTokenReady(true);
    }
  }, [clearSessionState, logger, oxyServices, storage, storageKeys.activeSessionId, storageKeys.sessionIds, switchSession, updateSessions]);
  (0, _react.useEffect)(() => {
    if (!storage || initializedRef.current) {
      return;
    }
    initializedRef.current = true;
    void restoreSessionsFromStorage();
  }, [restoreSessionsFromStorage, storage]);
  const activeSession = activeSessionId ? sessions.find(session => session.sessionId === activeSessionId) : undefined;
  const currentDeviceId = activeSession?.deviceId ?? null;
  const userId = user?.id;
  const refreshSessionsWithUser = (0, _react.useCallback)(() => refreshSessions(userId), [refreshSessions, userId]);
  const handleSessionRemoved = (0, _react.useCallback)(sessionId => {
    trackRemovedSession(sessionId);
  }, [trackRemovedSession]);
  const handleRemoteSignOut = (0, _react.useCallback)(() => {
    _sonner.toast.info('You have been signed out remotely.');
    logout().catch(remoteError => logger('Failed to process remote sign out', remoteError));
  }, [logger, logout]);
  (0, _useSessionSocket.useSessionSocket)({
    userId,
    activeSessionId,
    currentDeviceId,
    refreshSessions: refreshSessionsWithUser,
    logout,
    clearSessionState,
    baseURL: oxyServices.getBaseURL(),
    onRemoteSignOut: handleRemoteSignOut,
    onSessionRemoved: handleSessionRemoved
  });
  const switchSessionForContext = (0, _react.useCallback)(async sessionId => {
    await switchSession(sessionId);
  }, [switchSession]);

  // Create showBottomSheet function that uses the global function
  const showBottomSheetForContext = (0, _react.useCallback)(screenOrConfig => {
    (0, _bottomSheetManager.showBottomSheet)(screenOrConfig);
  }, []);
  const contextValue = (0, _react.useMemo)(() => ({
    user,
    sessions,
    activeSessionId,
    isAuthenticated,
    isLoading,
    isTokenReady: tokenReady,
    isStorageReady,
    error,
    currentLanguage,
    currentLanguageMetadata,
    currentLanguageName,
    currentNativeLanguageName,
    createIdentity,
    importIdentity,
    signIn,
    hasIdentity,
    getPublicKey,
    isIdentitySynced,
    syncIdentity,
    deleteIdentityAndClearAccount,
    identitySyncState: {
      isSynced: isIdentitySyncedStore ?? true,
      isSyncing: isSyncing ?? false
    },
    logout,
    logoutAll,
    switchSession: switchSessionForContext,
    removeSession: logout,
    refreshSessions: refreshSessionsWithUser,
    setLanguage,
    getDeviceSessions,
    logoutAllDeviceSessions,
    updateDeviceName,
    clearSessionState,
    clearAllAccountData,
    oxyServices,
    useFollow: useFollowHook,
    showBottomSheet: showBottomSheetForContext
  }), [activeSessionId, createIdentity, importIdentity, signIn, hasIdentity, getPublicKey, isIdentitySynced, syncIdentity, deleteIdentityAndClearAccount, isIdentitySyncedStore, isSyncing, currentLanguage, currentLanguageMetadata, currentLanguageName, currentNativeLanguageName, error, getDeviceSessions, isAuthenticated, isLoading, logout, logoutAll, logoutAllDeviceSessions, oxyServices, refreshSessionsWithUser, sessions, setLanguage, switchSessionForContext, tokenReady, isStorageReady, updateDeviceName, clearAllAccountData, useFollowHook, user, showBottomSheetForContext]);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(OxyContext.Provider, {
    value: contextValue,
    children: children
  });
};
exports.OxyProvider = OxyProvider;
const OxyContextProvider = exports.OxyContextProvider = OxyProvider;
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