/**
 * @fileOverview actions to set Investments state within the app and to
 * call the corresponding apis for listing transactions.
 */

import * as log from './log';
import { parseDate } from '../helper';

class InvestmentAction {
  constructor(store, grpc, nav, notification) {
    this._store = store;
    this._grpc = grpc;
    this._nav = nav;
    this._notification = notification;
  }

  /**
   * Initiate the transaction list view by navigating to the view and updating
   * the app's transaction state by calling all necessary grpc apis.
   * @return {undefined}
   */
  init() {
    this._nav.goInvestments();
    this.update();
  }

  /**
   * Select a transaction item from the transaction list view and then navigate
   * to the detail view to list transaction parameters.
   * @param  {Object} options.item The selected transaction object
   * @return {Promise<undefined>}
   */
  async select({ item }) {
    this._store.selectedTransaction = item;
    if (item.paymentRequest) {
      item.memo = await this.decodeMemo({ payReq: item.paymentRequest });
    }
    this._nav.goTransactionDetail();
    this.update();
  }

  /**
   * Update the on-chain transactions, invoice, and lighting payments in the
   * app state by querying all required grpc apis.
   * @return {Promise<undefined>}
   */
  async update() {
    await Promise.all([this.getAlgoTransactions()]);
  }

  /**
   * Get lock state.
   * @return {Promise<undefined>}
   */
  async updateLock(TransactionTime) {
    let locked = true;
    if (TransactionTime < new Date().setDate(new Date().getDate() - 1)) {
      locked = false;
    }
    return locked;
  }

  /**
   * List the on-chain transactions by calling the respective grpc api and updating
   * the transactions array in the global store.
   * @return {Promise<undefined>}
   */
  async getAlgoTransactions() {
    try {
      const { transactions } = await this._grpc.sendCommand('listInvoices');
      this._store.transactions = transactions.map(transaction => ({
        id: transaction.txHash,
        type: this.updateLock(transaction.timeStamp) ? 'locked' : 'unlocked',
        amount: transaction.amount,
        fee: transaction.totalFees,
        confirmations: transaction.numConfirmations,
        status: transaction.numConfirmations < 3 ? 'rewarded' : 'confirmed',
        date: parseDate(transaction.timeStamp),
      }));
    } catch (err) {
      log.error('Listing transactions failed', err);
    }
  }

  /**
   * Subscribe to incoming on-chain transactions using the grpc streaming api.
   * @return {Promise<undefined>}
   */
  async subscribeTransactions() {
    const stream = this._grpc.sendStreamCommand('subscribeTransactions');
    await new Promise((resolve, reject) => {
      stream.on('data', () => this.update());
      stream.on('end', resolve);
      stream.on('error', reject);
      stream.on('status', status => log.info(`Transactions update: ${status}`));
    });
  }
}

export default InvestmentAction;
