/*
 This file is part of GNU Taler
 (C) 2019 GNUnet e.V.
 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.
 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see 
 */
/**
 * Common interface of the internal wallet state.  This object is passed
 * to the various operations (exchange management, withdrawal, refresh, reserve
 * management, etc.).
 *
 * Some operations can be accessed via this state object.  This allows mutual
 * recursion between operations, without having cyclic dependencies between
 * the respective TypeScript files.
 *
 * (You can think of this as a "header file" for the wallet implementation.)
 */
/**
 * Imports.
 */
import {
  CancellationToken,
  CoinRefreshRequest,
  DenominationInfo,
  RefreshGroupId,
  RefreshReason,
  TransactionState,
  WalletNotification,
} from "@gnu-taler/taler-util";
import { HttpRequestLibrary } from "@gnu-taler/taler-util/http";
import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
import {
  ExchangeDetailsRecord,
  ExchangeRecord,
  RefreshReasonDetails,
  WalletStoresV1,
} from "./db.js";
import { AsyncCondition } from "./util/promiseUtils.js";
import {
  DbAccess,
  GetReadOnlyAccess,
  GetReadWriteAccess,
} from "./util/query.js";
import { TimerGroup } from "./util/timer.js";
import { WalletConfig } from "./wallet-api-types.js";
export const EXCHANGE_COINS_LOCK = "exchange-coins-lock";
export const EXCHANGE_RESERVES_LOCK = "exchange-reserves-lock";
export interface TrustInfo {
  isTrusted: boolean;
  isAudited: boolean;
}
export interface MerchantInfo {
  protocolVersionCurrent: number;
}
/**
 * Interface for merchant-related operations.
 */
export interface MerchantOperations {
  getMerchantInfo(
    ws: InternalWalletState,
    merchantBaseUrl: string,
  ): Promise;
}
export interface RefreshOperations {
  createRefreshGroup(
    ws: InternalWalletState,
    tx: GetReadWriteAccess<{
      denominations: typeof WalletStoresV1.denominations;
      coins: typeof WalletStoresV1.coins;
      refreshGroups: typeof WalletStoresV1.refreshGroups;
      coinAvailability: typeof WalletStoresV1.coinAvailability;
    }>,
    currency: string,
    oldCoinPubs: CoinRefreshRequest[],
    reason: RefreshReason,
    reasonDetails?: RefreshReasonDetails,
  ): Promise;
}
/**
 * Interface for exchange-related operations.
 */
export interface ExchangeOperations {
  // FIXME:  Should other operations maybe always use
  // updateExchangeFromUrl?
  getExchangeDetails(
    tx: GetReadOnlyAccess<{
      exchanges: typeof WalletStoresV1.exchanges;
      exchangeDetails: typeof WalletStoresV1.exchangeDetails;
    }>,
    exchangeBaseUrl: string,
  ): Promise;
  getExchangeTrust(
    ws: InternalWalletState,
    exchangeInfo: ExchangeRecord,
  ): Promise;
  updateExchangeFromUrl(
    ws: InternalWalletState,
    baseUrl: string,
    options?: {
      forceNow?: boolean;
      cancellationToken?: CancellationToken;
    },
  ): Promise<{
    exchange: ExchangeRecord;
    exchangeDetails: ExchangeDetailsRecord;
  }>;
}
export interface RecoupOperations {
  createRecoupGroup(
    ws: InternalWalletState,
    tx: GetReadWriteAccess<{
      recoupGroups: typeof WalletStoresV1.recoupGroups;
      denominations: typeof WalletStoresV1.denominations;
      refreshGroups: typeof WalletStoresV1.refreshGroups;
      coins: typeof WalletStoresV1.coins;
    }>,
    exchangeBaseUrl: string,
    coinPubs: string[],
  ): Promise;
}
export type NotificationListener = (n: WalletNotification) => void;
export interface ActiveLongpollInfo {
  [opId: string]: {
    cancel: () => void;
  };
}
export type CancelFn = () => void;
/**
 * Internal, shared wallet state that is used by the implementation
 * of wallet operations.
 *
 * FIXME:  This should not be exported anywhere from the taler-wallet-core package,
 * as it's an opaque implementation detail.
 */
export interface InternalWalletState {
  /**
   * Active longpoll operations.
   */
  activeLongpoll: ActiveLongpollInfo;
  cryptoApi: TalerCryptoInterface;
  timerGroup: TimerGroup;
  stopped: boolean;
  config: Readonly;
  /**
   * Asynchronous condition to interrupt the sleep of the
   * retry loop.
   *
   * Used to allow processing of new work faster.
   */
  workAvailable: AsyncCondition;
  listeners: NotificationListener[];
  initCalled: boolean;
  merchantInfoCache: Record;
  exchangeOps: ExchangeOperations;
  recoupOps: RecoupOperations;
  merchantOps: MerchantOperations;
  refreshOps: RefreshOperations;
  isTaskLoopRunning: boolean;
  getTransactionState(
    ws: InternalWalletState,
    tx: GetReadOnlyAccess,
    transactionId: string,
  ): Promise;
  getDenomInfo(
    ws: InternalWalletState,
    tx: GetReadOnlyAccess<{
      denominations: typeof WalletStoresV1.denominations;
    }>,
    exchangeBaseUrl: string,
    denomPubHash: string,
  ): Promise;
  db: DbAccess;
  http: HttpRequestLibrary;
  notify(n: WalletNotification): void;
  addNotificationListener(f: (n: WalletNotification) => void): CancelFn;
  /**
   * Stop ongoing processing.
   */
  stop(): void;
  /**
   * Run an async function after acquiring a list of locks, identified
   * by string tokens.
   */
  runSequentialized(tokens: string[], f: () => Promise): Promise;
  /**
   * Ensure that a task loop is currently running.
   * Starts one if no task loop is running.
   */
  ensureTaskLoopRunning(): void;
}