import dayjs from 'dayjs';

import { TQueryParams } from '../../models/QueryResult.model';
import { addHeaderToData } from '../../helpers/excel.helper';
import {
  addCustomerGroups,
  excludeNoDataColumns,
  findCollaterals,
  findCollateralSheets,
} from '../../db/collaterals.db';
import { ECollaterals } from '../../enums/collaterals.enum';
import mongoose from 'mongoose';
import { COLLATERALS } from '../../helpers/column-desciptions.helper';
import { BBCDateModel } from '../../models/BBCDate.model';
import { getPartialPaid } from './partially-paid-restated';

export const getGroupedReceivablesFull = async (params: TQueryParams) => {
  const data = await getGroupedReceivables(params);
  const header = getGroupedReceivablesHeader();
  return addHeaderToData(header, data);
};

export const getGroupedReceivables = async (params: TQueryParams) => {
  const { borrowerId, bbcDateId, extraParams } = params;
  const { calculateDueDate } = <{ calculateDueDate: boolean }>extraParams;
  const sheets = await findCollateralSheets(bbcDateId.toString(), ECollaterals.RECEIVABLE);

  return await Promise.all(sheets.map(async (sheet) => {
    const data: any[] = await findCollaterals(sheet._id.toString(), false);
    const customerTitleIndex = COLLATERALS[ECollaterals.RECEIVABLE].findIndex((column) => column.db_title === 'customerTitle');

    const columnsShort = COLLATERALS[ECollaterals.RECEIVABLE]
      .map((c) => ({ db_title: c.db_title, title: c.title }))
      .filter((c) => c.db_title !== 'bbcDate');
    columnsShort.splice(customerTitleIndex, 0, { db_title: 'customerGroup', title: 'Customer group' });
    columnsShort.push({ db_title: 'partiallyPaid', title: 'Partially paid' });

    const columnDB = columnsShort.map((c) => c.db_title);

    const bbcDate = await BBCDateModel.findById(bbcDateId).lean();
    const startDate = dayjs(new Date(bbcDate.bbcDate)).subtract(180, 'day').toDate();
    const endDate = new Date(bbcDate.bbcDate);

    const { partiallyPaidInvoices } = await getPartialPaid({ borrowerId: new mongoose.Types.ObjectId(borrowerId), startDate, endDate });

    const dataWithPartiallyPaid = data.map((invoice) => {
      let partiallyPaid = false;
      const foundInvoice = partiallyPaidInvoices.find((pInvoice) => {
        return (pInvoice.invoiceNumber === invoice.invoiceNumber) && (pInvoice.customer === invoice.customerTitle);
      });
      if (foundInvoice) {
        partiallyPaid = foundInvoice.difference > 0;
      }
      if ((invoice.originalAmount !== 0) && (invoice.originalAmount !== invoice.invoiceAmount)) {
        partiallyPaid = true;
      }
      return {
        ...invoice,
        partiallyPaid,
        dueDate: calculateDueDate ? dayjs(invoice.invoiceDate).utcOffset(0).add(90, 'days').toDate() : invoice.dueDate,
      };
    });

    const shortData = excludeNoDataColumns(dataWithPartiallyPaid, columnDB);
    const dataWithGroups = await addCustomerGroups(shortData, borrowerId.toString());
    return { [sheet.sheetName]: dataWithGroups };
  }));
};

const getGroupedReceivablesHeader = () => {
  return {
    sheetName: 'Sheet name',
    invoiceNumber: 'Invoice number',
    invoiceDate: 'Invoice date',
    customerTitle: 'Customer title',
    customerGroup: 'Customer group',
    invoiceAmount: 'Invoice amount',
    dueDate: 'Due date',
    invoiceDetail1: 'Invoice detail 1',
    invoiceDetail2: 'Invoice detail 2',
    invoiceDetail3: 'Invoice detail 3',
    partiallyPaid: 'Partially paid',
  };
};
