import React, {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import {
  createSavingsGoal,
  createSavingsTransaction,
  createSavingsTransactions,
  deleteSavingsGoal,
  getAllPayoutsTransactions,
  getAllSavingsTransactions,
  getSavingsGoals,
  setPayoutsTransactions,
  updateSavingsGoal,
} from '../app/functions/savings/savingsStorage';
import customUUID from '../app/functions/customUUID';
import {
  DEFAULT_GOAL_EMOJI,
  STARTING_INDEX_FOR_SAVINGS_DERIVE,
} from '../app/constants';
import {
  deriveSparkGiftMnemonic,
  deriveSparkIdentityKey,
  deriveSparkAddress,
} from '../app/functions/gift/deriveGiftWallet';
import {
  getLocalStorageItem,
  setLocalStorageItem,
} from '../app/functions/localStorage';
import { useKeysContext } from './keys';
import { useAppStatus } from './appStatus';
import {
  computeGoalBalanceMicros,
  computeSavingsBalanceMicros,
  fetchSavingsInterestPayouts,
  fromMicros,
  normalizeGoalForUI,
  resolveGoalAndAmount,
  serializeGoalMetadata,
  toLegacyDisplayTransaction,
  toMicros,
} from '../app/components/admin/homeComponents/savings/utils';
import {
  getBitcoinWithdrawls,
  getBitcoinBalance,
  initializeSparkWalletViewer,
  getTokensBalance,
  getTokenTransactions,
} from '../app/functions/spark/walletViewer';
import { useTranslation } from 'react-i18next';
import tokenBufferAmountToDecimal from '../app/functions/lrc20/bufferToDecimal';

const SavingsContext = createContext(null);

/**
 * @property {string} id
 * @property {string} name
 * @property {number} targetAmountMicros
 * @property {number} createdAt
 * @property {number} updatedAt
 * @property {string | null | undefined} [metadata]
 */

/**
 * @typedef {'deposit' | 'withdrawal'} SavingsTransactionType
 */

/**
 * @typedef {Object} SavingsTransaction
 * @property {string} id
 * @property {string} goalId
 * @property {SavingsTransactionType} type
 * @property {number} amountMicros
 * @property {number} timestamp
 */

// Sentinel goalId used when a deposit/withdrawal is made against the savings
// wallet directly (not attributed to any specific goal).
export const UNALLOCATED_GOAL_ID = 'unallocated';

const SAVINGS_BALANCE_CACHE_KEY = 'savings_wallet_balance_micros';
const SAVINGS_BITCOIN_BALANCE_CACHE_KEY = 'savings_wallet_bitcoin_balance_sats';
const SAVINGS_BALANCE_FETCH_TIME_KEY = 'savings_wallet_balance_fetch_time';
const SAVINGS_PAYOUTS_FETCH_TIME_KEY = 'savings_payouts_fetch_time';
const TX_RECONCILIATION_WINDOW_MS = 10 * 60 * 1000;

const coerceBalanceNumber = balance => {
  const candidate =
    balance?.balance ??
    balance?.availableBalance ??
    balance?.availableToSendBalance ??
    balance ??
    0;
  const parsed = Number(candidate);
  return Number.isFinite(parsed) ? parsed : 0;
};

const isLikelySameSavingsTransaction = (existingTx, sparkTx) => {
  if (existingTx?.id === sparkTx?.id) return true;
  if (existingTx?.type !== sparkTx?.type) return false;
  if (Number(existingTx?.amountMicros) !== Number(sparkTx?.amountMicros)) {
    return false;
  }

  return (
    Math.abs(Number(existingTx?.timestamp) - Number(sparkTx?.timestamp)) <=
    TX_RECONCILIATION_WINDOW_MS
  );
};

export function SavingsProvider({ children }) {
  const { accountMnemoinc } = useKeysContext();
  const { didGetToHomepage } = useAppStatus();

  const [goals, setGoals] = useState([]);
  const [transactions, setTransactions] = useState([]);
  const [savingsWallet, setSavingsWallet] = useState(null);
  const [walletBalanceMicros, setWalletBalanceMicros] = useState(null);
  const [walletBitcoinBalanceSats, setWalletBitcoinBalanceSats] =
    useState(null);
  const [interestPayouts, setInterestPayouts] = useState([]);
  const hasDerivedWalletRef = useRef(false);
  const savingsWalletMnemonicRef = useRef(null);
  const initPromiseRef = useRef(null);
  const hasInitializedRef = useRef(false);
  const [isInitializing, setIsInitializing] = useState(true);
  const [initializationError, setInitializationError] = useState(null);
  const { t } = useTranslation();
  // Set to true by recordTransaction after a successful deposit/withdrawal so
  // the next refreshBalances call knows the on-chain balance has changed.
  const balanceDirtyRef = useRef(false);
  // Timestamps (ms) of the last successful fetch — populated from AsyncStorage on load.
  const balanceFetchTimeRef = useRef(0);
  const payoutFetchTimeRef = useRef(0);

  const updateWalletBalance = useCallback(micros => {
    const now = String(Date.now());
    setWalletBalanceMicros(micros);
    setLocalStorageItem(SAVINGS_BALANCE_CACHE_KEY, String(micros));
    setLocalStorageItem(SAVINGS_BALANCE_FETCH_TIME_KEY, now);
  }, []);

  const updateWalletBitcoinBalance = useCallback(sats => {
    setWalletBitcoinBalanceSats(sats);
    setLocalStorageItem(SAVINGS_BITCOIN_BALANCE_CACHE_KEY, String(sats));
  }, []);

  const deriveSingleSavingsWallet = useCallback(async () => {
    if (hasDerivedWalletRef.current) return savingsWallet;
    if (!accountMnemoinc) return null;

    try {
      const step1 = await deriveSparkGiftMnemonic(
        accountMnemoinc,
        STARTING_INDEX_FOR_SAVINGS_DERIVE,
      );

      if (!step1?.success) {
        throw new Error(step1?.error);
      }

      const step2 = await deriveSparkIdentityKey(step1.derivedMnemonic, 1);

      if (!step2?.success) {
        throw new Error(step2?.error);
      }

      const sparkAddr = deriveSparkAddress(step2.publicKey);

      if (!sparkAddr?.success) {
        throw new Error(sparkAddr?.error);
      }

      const derivedWallet = {
        derivationIndex: STARTING_INDEX_FOR_SAVINGS_DERIVE,
        identityPublicKeyHex: step2.publicKeyHex,
        sparkAddress: sparkAddr.address,
      };

      savingsWalletMnemonicRef.current = step1.derivedMnemonic;
      hasDerivedWalletRef.current = true;
      setSavingsWallet(derivedWallet);
      return derivedWallet;
    } catch (deriveError) {
      return null;
    }
  }, [accountMnemoinc, savingsWallet]);

  const loadSavingsState = useCallback(async () => {
    try {
      // Load cached balance immediately so UI renders without loading state
      const [
        cachedBalance,
        cachedBitcoinBalance,
        cachedBalanceFetchTime,
        cachedPayoutFetchTime,
      ] = await Promise.all([
        getLocalStorageItem(SAVINGS_BALANCE_CACHE_KEY),
        getLocalStorageItem(SAVINGS_BITCOIN_BALANCE_CACHE_KEY),
        getLocalStorageItem(SAVINGS_BALANCE_FETCH_TIME_KEY),
        getLocalStorageItem(SAVINGS_PAYOUTS_FETCH_TIME_KEY),
      ]);

      if (cachedBalance !== null && cachedBalance !== undefined) {
        const parsed = Number(cachedBalance);
        if (Number.isFinite(parsed)) {
          setWalletBalanceMicros(parsed);
        }
      }

      if (cachedBitcoinBalance !== null && cachedBitcoinBalance !== undefined) {
        const parsed = Number(cachedBitcoinBalance);
        if (Number.isFinite(parsed)) {
          setWalletBitcoinBalanceSats(parsed);
        }
      }

      // Restore cached timestamps into refs so the refresh gates work on first focus
      if (cachedBalanceFetchTime) {
        balanceFetchTimeRef.current = Number(cachedBalanceFetchTime);
      }
      if (cachedPayoutFetchTime) {
        payoutFetchTimeRef.current = Number(cachedPayoutFetchTime);
      }

      const derivedWallet = await deriveSingleSavingsWallet();
      const [
        goalsFromStorage,
        transactionsFromStorage,
        payoutsTransactionsFromStorage,
      ] = await Promise.all([
        getSavingsGoals(),
        getAllSavingsTransactions(),
        getAllPayoutsTransactions(),
      ]);

      setGoals(goalsFromStorage);
      setTransactions(transactionsFromStorage);
      setInterestPayouts(payoutsTransactionsFromStorage);
      console.log('savigs loaded succesfully');
      return {
        didWork: true,
        savingsWallet: derivedWallet || savingsWallet,
        goals: goalsFromStorage,
        transactions: transactionsFromStorage,
        interestPayouts: payoutsTransactionsFromStorage,
      };
    } catch (loadError) {
      console.log(loadError, 'loading savings errro');
      return { didWork: false, error: loadError?.message };
    }
  }, [deriveSingleSavingsWallet, savingsWallet]);

  const createGoal = useCallback(async payload => {
    try {
      const name = String(payload?.name || '').trim();
      if (!name) {
        return {
          didWork: false,
          error: t('savings.howItWorks.context.goalNameRequired'),
        };
      }

      const now = Date.now();
      const nextGoal = {
        id: payload?.id || customUUID(),
        name,
        targetAmountMicros: Math.max(
          0,
          Math.round(
            Number(
              payload?.targetAmountMicros ??
                toMicros(payload?.targetAmount ?? payload?.amount ?? 0),
            ),
          ),
        ),
        createdAt: now,
        updatedAt: now,
        metadata: serializeGoalMetadata({
          emoji: payload?.emoji || DEFAULT_GOAL_EMOJI,
        }),
      };

      const createdGoal = await createSavingsGoal(nextGoal);

      setGoals(prev => [createdGoal, ...prev]);

      return { didWork: true, goal: createdGoal };
    } catch (createError) {
      return { didWork: false, error: createError.message };
    }
  }, []);

  const updateGoal = useCallback(async (goalId, patch) => {
    try {
      const metadata =
        patch && Object.prototype.hasOwnProperty.call(patch, 'emoji')
          ? serializeGoalMetadata({ emoji: patch.emoji || DEFAULT_GOAL_EMOJI })
          : undefined;

      const updatedGoal = await updateSavingsGoal(goalId, {
        name: patch?.name,
        targetAmountMicros:
          patch?.targetAmountMicros ??
          (patch?.amount != null ? toMicros(patch.amount) : undefined),
        metadata,
      });

      if (!updatedGoal) {
        return { didWork: false, error: t('savings.context.goalNotFound') };
      }

      setGoals(prev =>
        prev.map(goal => (goal.id === goalId ? updatedGoal : goal)),
      );
      return { didWork: true, goal: updatedGoal };
    } catch (updateError) {
      return { didWork: false, error: updateError.message };
    }
  }, []);

  const removeGoal = useCallback(
    async goalId => {
      try {
        const targetGoalId = goalId;

        const didDelete = await deleteSavingsGoal(targetGoalId);
        if (!didDelete) {
          return { didWork: false, error: t('savings.context.goalNotFound') };
        }

        const nextGoals = goals.filter(goal => goal.id !== targetGoalId);
        setGoals(nextGoals);
        setTransactions(prev => prev.filter(tx => tx.goalId !== targetGoalId));

        return { didWork: true };
      } catch (removeError) {
        return { didWork: false, error: removeError.message };
      }
    },
    [goals],
  );

  const recordTransaction = useCallback(
    async ({ goalId, type, amount }) => {
      try {
        // Resolve the effective goalId: null / undefined / UNALLOCATED_GOAL_ID
        // all mean "no specific goal — record against the wallet directly".
        const resolvedGoalId =
          goalId && goalId !== UNALLOCATED_GOAL_ID
            ? goalId
            : UNALLOCATED_GOAL_ID;

        // For goal-attributed transactions, verify the goal still exists.
        if (resolvedGoalId !== UNALLOCATED_GOAL_ID) {
          const goal = goals.find(item => item.id === resolvedGoalId);
          if (!goal)
            return { didWork: false, error: t('savings.context.goalNotFound') };
        }

        const amountMicros =
          amount != null && amount > 0
            ? toMicros(amount)
            : Math.round(Number(amount || 0));

        if (type === 'withdrawal') {
          // For goal-specific withdrawals validate against the goal's tracked balance.
          // For unallocated withdrawals validate against the live wallet balance.
          const availableMicros =
            resolvedGoalId !== UNALLOCATED_GOAL_ID
              ? computeGoalBalanceMicros(resolvedGoalId, transactions)
              : walletBalanceMicros ??
                computeSavingsBalanceMicros(transactions);
        }

        const transaction = await createSavingsTransaction({
          id: customUUID(),
          goalId: resolvedGoalId,
          type,
          amountMicros,
          timestamp: Date.now(),
        });

        setTransactions(prev => [transaction, ...prev]);
        // Mark balance as dirty so the next screen-focus triggers a live refetch
        balanceDirtyRef.current = true;

        return { didWork: true, transaction };
      } catch (transactionError) {
        return { didWork: false, error: transactionError.message };
      }
    },
    [goals, transactions, walletBalanceMicros],
  );

  const contributeToGoal = useCallback(
    async (goalIdOrPayload, maybeAmount) => {
      const { goalId, amount } = resolveGoalAndAmount(
        goalIdOrPayload,
        maybeAmount,
      );
      // goalId may be a specific goal id, UNALLOCATED_GOAL_ID, or absent —
      // recordTransaction normalises all absent/unallocated cases internally.
      return recordTransaction({
        goalId: goalId || UNALLOCATED_GOAL_ID,
        type: 'deposit',
        amount,
      });
    },
    [recordTransaction],
  );

  const withdrawFromGoal = useCallback(
    async (goalIdOrPayload, maybeAmount) => {
      const { goalId, amount } = resolveGoalAndAmount(
        goalIdOrPayload,
        maybeAmount,
      );
      return recordTransaction({
        goalId: goalId || UNALLOCATED_GOAL_ID,
        type: 'withdrawal',
        amount,
      });
    },
    [recordTransaction],
  );

  const withdrawlFromRewards = useCallback(
    async amount => {
      return recordTransaction({
        goalId: UNALLOCATED_GOAL_ID,
        type: 'bitcoinWithdrawal',
        amount,
      });
    },
    [recordTransaction],
  );

  const savingsGoals = useMemo(
    () =>
      goals.map(goal => {
        const normalizedGoal = normalizeGoalForUI(goal);
        return {
          ...normalizedGoal,
          currentAmountMicros: computeGoalBalanceMicros(goal.id, transactions),
        };
      }),
    [goals, transactions],
  );

  const totalGoalsBalance = useMemo(
    () =>
      fromMicros(
        savingsGoals.reduce((goalA, goalB) => {
          return goalA + goalB.currentAmountMicros;
        }, 0),
      ),
    [savingsGoals, transactions],
  );

  const allSavingsTransactions = useMemo(() => {
    const goalNameById = new Map(goals.map(goal => [goal.id, goal.name]));
    return transactions.map(tx =>
      toLegacyDisplayTransaction(tx, goalNameById.get(tx.goalId), t),
    );
  }, [goals, transactions, t]);

  const restorePaymentsFromSpark = useCallback(
    async ({ tokenTransactions, bitcoinWithdrawls, wallet } = {}) => {
      try {
        const activeWallet = wallet || savingsWallet;
        if (!activeWallet?.sparkAddress) return;

        const [pastTxs, pastBitcoinTxs] =
          tokenTransactions || bitcoinWithdrawls
            ? [tokenTransactions, bitcoinWithdrawls]
            : await Promise.all([
                getTokenTransactions(activeWallet.sparkAddress),
                getBitcoinWithdrawls(activeWallet.sparkAddress),
              ]);

        const tokenTxs = (pastTxs?.transactions ?? [])
          .slice(0, 50)
          .reduce((acc, tokenTx) => {
            const tokenOutputs = tokenTx.tokenTransaction?.tokenOutputs;
            if (!tokenOutputs?.length) return acc;

            const txHash = Buffer.from(
              Object.values(tokenTx.tokenTransactionHash),
            ).toString('hex');

            const ownerPublicKey = Buffer.from(
              Object.values(tokenOutputs[0]?.ownerPublicKey),
            ).toString('hex');

            const amountMicros = tokenOutputs[0]?.tokenAmount
              ? Number(tokenBufferAmountToDecimal(tokenOutputs[0].tokenAmount))
              : 0;

            if (!amountMicros) return acc;

            acc.push({
              id: txHash,
              goalId: UNALLOCATED_GOAL_ID,
              type:
                ownerPublicKey !== activeWallet.identityPublicKeyHex
                  ? 'withdrawal'
                  : 'deposit',
              amountMicros,
              timestamp: new Date(
                tokenTx.tokenTransaction.clientCreatedTimestamp,
              ).getTime(),
            });

            return acc;
          }, []);

        const bitcoinTxs = (pastBitcoinTxs?.transfers ?? [])
          .filter(
            transfer =>
              Buffer.from(transfer.senderIdentityPublicKey).toString('hex') ===
              activeWallet.identityPublicKeyHex,
          )
          .map(tx => ({
            id: tx.id,
            goalId: UNALLOCATED_GOAL_ID,
            type: 'bitcoinWithdrawal',
            amountMicros: toMicros(tx.totalValue),
            timestamp: new Date(tx.createdTime).getTime(),
          }));

        const newTxs = [...tokenTxs, ...bitcoinTxs];
        const existingTxs = await getAllSavingsTransactions();
        const txsToSave = newTxs.filter(
          sparkTx =>
            !existingTxs.some(existingTx =>
              isLikelySameSavingsTransaction(existingTx, sparkTx),
            ),
        );

        if (txsToSave.length) {
          await createSavingsTransactions(txsToSave);
        }

        setTransactions(await getAllSavingsTransactions());
      } catch (err) {
        console.error('error restoring tx history', err);
      }
    },
    [savingsWallet],
  );

  const refreshBalances = useCallback(
    async ({ force = false } = {}) => {
      if (!savingsWallet?.sparkAddress) return { didWork: false };

      const viewerReady = await initializeSparkWalletViewer(
        savingsWalletMnemonicRef.current || accountMnemoinc,
      );
      if (!viewerReady) return { didWork: false };

      const [balance, bitcoinBalance] = await Promise.all([
        getTokensBalance(savingsWallet.sparkAddress),
        getBitcoinBalance(savingsWallet.sparkAddress),
      ]);

      await restorePaymentsFromSpark();
      updateWalletBalance(coerceBalanceNumber(balance));
      updateWalletBitcoinBalance(coerceBalanceNumber(bitcoinBalance));

      return { didWork: true };
    },
    [
      savingsWallet,
      accountMnemoinc,
      updateWalletBalance,
      updateWalletBitcoinBalance,
      restorePaymentsFromSpark,
    ],
  );

  const refreshInterestPayouts = useCallback(
    async ({ force = false } = {}) => {
      if (!savingsWallet?.identityPublicKeyHex) return { didWork: false };

      const payouts = await fetchSavingsInterestPayouts(
        savingsWallet.identityPublicKeyHex,
      );

      setPayoutsTransactions(payouts);
      setInterestPayouts(payouts);

      return { didWork: true };
    },
    [savingsWallet],
  );

  const initializeSavings = useCallback(
    async ({ force = false } = {}) => {
      if (initPromiseRef.current) return initPromiseRef.current;
      if (hasInitializedRef.current && !force) {
        return { didWork: true, skipped: true };
      }

      const shouldShowInitializing = !hasInitializedRef.current;
      if (shouldShowInitializing) {
        setIsInitializing(true);
      }

      const initPromise = (async () => {
        try {
          setInitializationError(null);
          const loadedState = await loadSavingsState();
          const activeWallet = loadedState?.savingsWallet || savingsWallet;

          if (!activeWallet?.sparkAddress) {
            const message = 'Savings wallet unavailable';
            setInitializationError(message);
            return { didWork: false, error: message };
          }

          const viewerReady = await initializeSparkWalletViewer(
            savingsWalletMnemonicRef.current || accountMnemoinc,
          );

          if (!viewerReady) {
            const message = 'Spark wallet viewer unavailable';
            setInitializationError(message);
            return { didWork: false, error: message };
          }

          const [
            tokenBalance,
            bitcoinBalance,
            tokenTransactions,
            bitcoinWithdrawls,
            payouts,
          ] = await Promise.all([
            getTokensBalance(activeWallet.sparkAddress),
            getBitcoinBalance(activeWallet.sparkAddress),
            getTokenTransactions(activeWallet.sparkAddress),
            getBitcoinWithdrawls(activeWallet.sparkAddress),
            activeWallet.identityPublicKeyHex
              ? fetchSavingsInterestPayouts(activeWallet.identityPublicKeyHex)
              : Promise.resolve([]),
          ]);

          updateWalletBalance(coerceBalanceNumber(tokenBalance));
          updateWalletBitcoinBalance(coerceBalanceNumber(bitcoinBalance));

          await restorePaymentsFromSpark({
            tokenTransactions,
            bitcoinWithdrawls,
            wallet: activeWallet,
          });

          await setPayoutsTransactions(payouts);
          setInterestPayouts(payouts);
          setLocalStorageItem(
            SAVINGS_PAYOUTS_FETCH_TIME_KEY,
            String(Date.now()),
          );

          return { didWork: true };
        } catch (initError) {
          const message = initError?.message || 'Unable to initialize savings';
          setInitializationError(message);
          console.log(initError, 'initializing savings error');
          return { didWork: false, error: message };
        } finally {
          hasInitializedRef.current = true;
          initPromiseRef.current = null;
          if (shouldShowInitializing) {
            setIsInitializing(false);
          }
        }
      })();

      initPromiseRef.current = initPromise;
      return initPromise;
    },
    [
      accountMnemoinc,
      loadSavingsState,
      restorePaymentsFromSpark,
      savingsWallet,
      updateWalletBalance,
      updateWalletBitcoinBalance,
    ],
  );

  useEffect(() => {
    if (!didGetToHomepage) return;
    initializeSavings();
  }, [initializeSavings, didGetToHomepage]);

  const savingsBalanceMicros = useMemo(() => {
    // Live wallet balance is the source of truth (survives goal deletion)
    if (walletBalanceMicros !== null) {
      return walletBalanceMicros;
    }
    // Fallback to local transaction sum while API hasn't returned yet
    return computeSavingsBalanceMicros(transactions);
  }, [walletBalanceMicros, transactions]);

  const totalIntrestEarned = useMemo(() => {
    return interestPayouts?.reduce((prev, curr) => prev + curr.payoutSats, 0);
  }, [interestPayouts.length]);

  const value = useMemo(
    () => ({
      deriveSingleSavingsWallet,
      savingsGoals,
      allSavingsTransactions,
      getGoalBalanceMicros: goalId =>
        computeGoalBalanceMicros(goalId, transactions),
      // Compatibility with existing UI calls.
      savingsBalance: fromMicros(savingsBalanceMicros),
      setSavingsGoal: async ({ name, amount, emoji, mode, goalId }) => {
        const shouldUpdate = mode === 'update' || !!goalId;
        if (shouldUpdate) {
          const targetGoalId = goalId;
          if (!targetGoalId) {
            return { didWork: false, error: t('savings.context.goalNotFound') };
          }
          return updateGoal(targetGoalId, { name, amount, emoji });
        }

        // Default behavior: create a new logical goal so multiple goals can coexist.
        return createGoal({ name, amount, emoji });
      },
      removeSavingsGoal: removeGoal,
      addMoney: async ({ amount, goalId }) =>
        contributeToGoal({ amount, goalId }),
      withdrawMoney: async ({ amount, goalId }) =>
        withdrawFromGoal({ amount, goalId }),
      withdrawlFromRewards,
      initializeSavings,
      refreshSavings: loadSavingsState,
      refreshBalances,
      refreshInterestPayouts,
      interestPayouts,
      walletBalanceMicros,
      walletBitcoinBalanceSats,
      savingsWallet,
      totalGoalsBalance,
      totalIntrestEarned,
      isInitializing,
      initializationError,
    }),
    [
      deriveSingleSavingsWallet,
      createGoal,
      contributeToGoal,
      withdrawFromGoal,
      withdrawlFromRewards,
      savingsGoals,
      allSavingsTransactions,
      transactions,
      savingsBalanceMicros,
      updateGoal,
      removeGoal,
      initializeSavings,
      loadSavingsState,
      refreshBalances,
      refreshInterestPayouts,
      interestPayouts,
      walletBalanceMicros,
      walletBitcoinBalanceSats,
      savingsWallet,
      totalGoalsBalance,
      totalIntrestEarned,
      isInitializing,
      initializationError,
    ],
  );

  return (
    <SavingsContext.Provider value={value}>{children}</SavingsContext.Provider>
  );
}

export function useSavings() {
  return useContext(SavingsContext);
}
