import mongoose from 'mongoose';

import {
  ILoanTransactionDoc,
  ILoanTransactionView,
  ILoanTransactionViewWithBank,
  ITransactionsFilter,
  LoanTransaction,
} from '../models/LoanTransaction.model';
import { fieldsToUnset, getLoanProducts } from './loan-products.db';
import { ITEMS_PAGINATION } from './collaterals.db';
import { IPaginatorOptions } from '../interfaces/collaterals.interface';

export const getLastTransactionForDate = async (productId: string, date: Date = new Date(), excludeAdjustments = false) => {
  const excludeFilter = excludeAdjustments
    ? {
      'transactionType': {
        $nin: ['ADJUSTMENT'],
      },
    }
    : {};
  const lastTransaction = await LoanTransaction.aggregate<ILoanTransactionDoc>([
    {
      $match: {
        'productId': new mongoose.Types.ObjectId(productId),
        'date': { $lte: date },
        ...excludeFilter,
      },
    }, {
      $sort: {
        'date': -1,
        'order': -1,
        'createdAt': -1,
      },
    }, {
      $limit: 1,
    },
  ]);
  if (!lastTransaction.length) {
    return null;
  }
  return lastTransaction[0];
};

export const getLoanTransactions = async <T extends boolean>(transactionsFilter: ITransactionsFilter, paginatorOptions: IPaginatorOptions, withBanks: T, isReverse = false, isMinified = false) => {
  const borrowerProducts = await getLoanProducts(transactionsFilter.borrowerId);
  const productIds = borrowerProducts
    .filter((product) => transactionsFilter.productId ? product._id.toString() === transactionsFilter.productId : true)
    .map((product) => product._id);

  const optionalFilters = [];
  if (transactionsFilter.amount) {
    optionalFilters.push({ 'amount': transactionsFilter.amount });
  }
  if (transactionsFilter.reference) {
    optionalFilters.push({ 'reference': { $regex: transactionsFilter.reference, $options: 'i' } });
  }
  const bankLookup = !withBanks
    ? []
    : [
      {
        $lookup: {
          from: 'banks',
          localField: 'bankId',
          foreignField: '_id',
          as: 'bank',
        },
      }, {
        $unwind: {
          path: '$bank',
          preserveNullAndEmptyArrays: true,
        },
      },
    ];

  const projectedFields = isMinified
    ? [{ $project: { _id: 1, date: 1, amount: 1, reference: 1, balance: 1, transactionType: 1 } }]
    : [];

  return LoanTransaction.aggregate<T extends true ? ILoanTransactionViewWithBank : ILoanTransactionView>([
    {
      $match: {
        $and: [
          { 'date': { $gte: transactionsFilter.periodStart } },
          { 'date': { $lte: transactionsFilter.periodEnd } },
          { 'productId': { $in: productIds } },
          ...optionalFilters,
        ],
      },
    }, {
      $sort: {
        'date': isReverse ? -1 : 1,
        'order': isReverse ? -1 : 1,
        'createdAt': isReverse ? -1 : 1,
      },
    },
    ...ITEMS_PAGINATION(paginatorOptions),
    ...bankLookup,
    {
      $unset: fieldsToUnset,
    },
    ...projectedFields,
  ]);
};
