import { Bank, IBankView, IBankWithId } from '../models/Banks.model';

import { QuickbooksAccount } from '../models/QuickbooksAccount.model';

const fieldsToUnset = ['order', '__v', 'createdAt', 'updatedAt'];

export class BanksService {

  async getBanks() {
    return Bank.aggregate<IBankView>([
      {
        $sort: {
          'order': 1,
        },
      }, {
        $unset: fieldsToUnset,
      }, {
        $addFields: {
          valid: true,
        },
      },
    ]);
  }

  async createBank(bank: IBankView) {
    const newBank = new Bank(bank);
    await newBank.save();
  }

  async editBank(bank: IBankView) {
    await Bank.findByIdAndUpdate(bank._id, bank);
  }

  async findBankByNumber(bankAccountNumber: string) {
    return Bank.findOne({ bankAccountNumber }).lean();
  }

  async findBankByAccountCode(accountCode: string) {
    const account = await QuickbooksAccount.findOne({ accountCode }).lean();
    if (!account) {
      return null;
    }
    const banks: IBankWithId[] = await Bank.aggregate([
      {
        '$match': {
          '$expr': {
            '$gt': [
              {
                '$size': {
                  '$filter': {
                    'input': {
                      '$objectToArray': '$ledgerAccountCodes',
                    },
                    'as': 'entry',
                    'cond': {
                      '$eq': [
                        '$$entry.v', account._id,
                      ],
                    },
                  },
                },
              }, 0,
            ],
          },
        },
      }, {
        '$sort': {
          'bankAccountNumber': 1,
        },
      }, {
        '$limit': 1,
      },
    ]);
    if (banks.length > 0) {
      return banks[0];
    }
    return null;
  }

  async updateBanks(banks: IBankView[]) {
    const existingBanks = await Bank.find().lean();
    const existingBankIds: string[] = existingBanks.map((bank) => bank._id.toString());
    const updatedBankIds: string[] = banks.map((bank) => bank._id.toString());
    const idsToRemove = existingBankIds.filter((id) => !updatedBankIds.includes(id));
    await Promise.all(banks.map(async (bank) => {
      const { _id, ...rest } = bank;
      if (_id.toString().includes('new_')) {
        await this.createBank({ _id: null, ...rest });
      } else {
        await this.editBank(bank);
      }
    }));
    await Bank.updateMany({ _id: { $in: idsToRemove } }, { isDeleted: true });
  }
}
