// Dont remove the following import line or the pin check will fail when opening askar waller
import { askar } from '@openwallet-foundation/askar-react-native';
import 'reflect-metadata';
import { DeviceEventEmitter } from 'react-native';
import { AskarWallet } from '@credo-ts/askar';
import { ConsoleLogger, LogLevel, SigningProviderRegistry } from '@credo-ts/core';
import { agentDependencies } from '@credo-ts/react-native';
import React, { createContext, useCallback, useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { DispatchAction } from './reducers/store';
import { useStore } from './store';
import { isBiometricsActive, loadWalletSalt, loadWalletSecret, secretForPIN, storeWalletSecret, wipeWalletKey } from '../services/keychain';
import { migrateToAskar } from '../utils/migration';
import { BifoldError } from '../types/error';
import { EventTypes } from '../constants';
import { useServices, TOKENS } from '../container-api';
import { AskarModuleConfig } from '@credo-ts/askar/build/AskarModuleConfig';
export const AuthContext = /*#__PURE__*/createContext(null);
export let LockoutReason = /*#__PURE__*/function (LockoutReason) {
  LockoutReason["Timeout"] = "Timeout";
  LockoutReason["Logout"] = "Logout";
  return LockoutReason;
}({});
export const AuthProvider = ({
  children
}) => {
  const [walletSecret, setWalletSecret] = useState();
  const [store, dispatch] = useStore();
  const {
    t
  } = useTranslation();
  const [hashPIN] = useServices([TOKENS.FN_PIN_HASH_ALGORITHM]);
  const setPIN = useCallback(async PIN => {
    const secret = await secretForPIN(PIN, hashPIN);
    await storeWalletSecret(secret);
  }, [hashPIN]);
  const getWalletSecret = useCallback(async () => {
    if (walletSecret) {
      return walletSecret;
    }
    const secret = await loadWalletSecret(t('Biometry.UnlockPromptTitle'), t('Biometry.UnlockPromptDescription'));
    setWalletSecret(secret);
    return secret;
  }, [t, walletSecret]);
  const commitWalletToKeychain = useCallback(async useBiometry => {
    const secret = await getWalletSecret();
    if (!secret) {
      return false;
    }

    // set did authenticate to true if we can get wallet credentials
    dispatch({
      type: DispatchAction.DID_AUTHENTICATE
    });
    if (useBiometry) {
      await storeWalletSecret(secret, useBiometry);
    } else {
      // erase wallet key if biometrics is disabled
      await wipeWalletKey(useBiometry);
    }
    return true;
  }, [dispatch, getWalletSecret]);
  const checkWalletPIN = useCallback(async PIN => {
    try {
      const secret = await loadWalletSalt();
      if (!(secret !== null && secret !== void 0 && secret.salt)) {
        return false;
      }
      const hash = await hashPIN(PIN, secret.salt);
      if (!store.migration.didMigrateToAskar) {
        await migrateToAskar(secret.id, hash);
        dispatch({
          type: DispatchAction.DID_MIGRATE_TO_ASKAR
        });
      }

      // NOTE: We create an instance of AskarWallet, which is the underlying wallet that powers the app
      // we then open that instance with the provided id and key to verify their integrity
      const askarWallet = new AskarWallet(new ConsoleLogger(LogLevel.off), new agentDependencies.FileSystem(), new SigningProviderRegistry([]), new AskarModuleConfig({
        ariesAskar: askar
      }));
      await askarWallet.open({
        id: secret.id,
        key: hash
      });
      await askarWallet.close();
      setWalletSecret({
        id: secret.id,
        key: hash,
        salt: secret.salt
      });
      return true;
    } catch {
      return false;
    }
  }, [dispatch, store.migration.didMigrateToAskar, hashPIN]);
  const removeSavedWalletSecret = useCallback(() => {
    setWalletSecret(undefined);
  }, []);
  const lockOutUser = useCallback(reason => {
    removeSavedWalletSecret();
    dispatch({
      type: DispatchAction.DID_AUTHENTICATE,
      payload: [false]
    });
    dispatch({
      type: DispatchAction.LOCKOUT_UPDATED,
      payload: [{
        displayNotification: reason === LockoutReason.Timeout
      }]
    });
  }, [removeSavedWalletSecret, dispatch]);
  const disableBiometrics = useCallback(async () => {
    await wipeWalletKey(true);
  }, []);
  const rekeyWallet = useCallback(async (agent, oldPin, newPin, useBiometry) => {
    try {
      if (!agent) {
        // no agent set, cannot rekey the wallet
        return false;
      }
      // argon2.hash can sometimes generate an error
      const secret = await loadWalletSalt();
      if (!secret) {
        return false;
      }
      const oldHash = await hashPIN(oldPin, secret.salt);
      const newSecret = await secretForPIN(newPin, hashPIN);
      const newHash = await hashPIN(newPin, newSecret.salt);
      if (!newSecret.key) {
        return false;
      }
      await agent.wallet.close();
      // wallet.rotateKey calls open under the hood
      await agent.wallet.rotateKey({
        id: secret.id,
        key: oldHash,
        rekey: newHash
      });
      await storeWalletSecret(newSecret, useBiometry);
      setWalletSecret(newSecret);
    } catch {
      return false;
    }
    return true;
  }, [hashPIN]);
  const verifyPIN = useCallback(async PIN => {
    try {
      const credentials = await getWalletSecret();
      if (!credentials) {
        throw new Error('Get wallet credentials error');
      }
      const key = await hashPIN(PIN, credentials.salt);
      if (credentials.key !== key) {
        return false;
      }
      return true;
    } catch (err) {
      const error = new BifoldError(t('Error.Title1042'), t('Error.Message1042'), (err === null || err === void 0 ? void 0 : err.message) ?? err, 1042);
      DeviceEventEmitter.emit(EventTypes.ERROR_ADDED, error);
      return false;
    }
  }, [getWalletSecret, t, hashPIN]);
  return /*#__PURE__*/React.createElement(AuthContext.Provider, {
    value: {
      lockOutUser,
      checkWalletPIN,
      getWalletSecret,
      removeSavedWalletSecret,
      disableBiometrics,
      commitWalletToKeychain,
      setPIN,
      isBiometricsActive,
      rekeyWallet,
      walletSecret,
      verifyPIN
    }
  }, children);
};
export const useAuth = () => useContext(AuthContext);
//# sourceMappingURL=auth.js.map