import mongoose from 'mongoose';
import Decimal from 'decimal.js';

import { ECollaterals } from '../enums/collaterals.enum';
import { getBBCDateDoc } from '../db/bbcDates.db';

import {
  copyCollateralAdjustmentWithoutSaving,
  getCollateralAdjustmentDocs,
  getLastCollateralAdjustmentDocs,
  saveCollateralAdjustmentDoc,
} from '../db/collateral-adjustments.db';
import {
  ICollateralAdjustment,
  ICollateralAdjustmentItem,
  ICollateralAdjustmentSummary,
} from '../models/CollateralAdjustment.model';
import { SignsService } from './signs.service';

export class CollateralAdjustmentsService {

  constructor(
    private readonly signsService: SignsService,
  ) {
  }

  async getCollateralAdjustmentSummary(bbcDateId: string): Promise<ICollateralAdjustmentSummary> {
    const bbcDateIdID = new mongoose.Types.ObjectId(bbcDateId);
    const collateralAdjustments = await getCollateralAdjustmentDocs([bbcDateIdID]);
    if (!collateralAdjustments.length) {
      return {};
    }
    return collateralAdjustments[0].summary;
  }

  async getCollateralAdjustment(bbcDateId: string): Promise<ICollateralAdjustment> {
    const bbcDateIdID = new mongoose.Types.ObjectId(bbcDateId);
    const cCollateralAdjustments = await getCollateralAdjustmentDocs([bbcDateIdID]);
    if (!!cCollateralAdjustments.length) {
      return cCollateralAdjustments.pop();
    }
    const lastItems = await this.getLastCopyCollateralAdjustmentItems(bbcDateId);
    const isBBCLockedResult = await this.signsService.isBBCLocked(bbcDateId);
    if (isBBCLockedResult) {
      const summary = this.calculateSummary(lastItems);
      return await copyCollateralAdjustmentWithoutSaving(bbcDateIdID, lastItems, summary);
    }
    return this.saveCollateralAdjustment(bbcDateId, { items: lastItems, notes: '' });
  }

  async saveCollateralAdjustment(bbcDateId: string, collateralAdjustmentsUpdate: Partial<ICollateralAdjustment>) {
    const isBBCLockedResult = await this.signsService.isBBCLocked(bbcDateId);
    if (isBBCLockedResult) {
      return null;
    }
    const summary = this.calculateSummary(collateralAdjustmentsUpdate.items);
    return await saveCollateralAdjustmentDoc(new mongoose.Types.ObjectId(bbcDateId), {
      ...collateralAdjustmentsUpdate,
      summary,
    });
  };

  async getLastCopyCollateralAdjustmentItems(bbcDateId: string) {
    const { borrowerId } = await getBBCDateDoc(bbcDateId.toString());
    const collateralAdjustmentDocs = await getLastCollateralAdjustmentDocs(bbcDateId, borrowerId.toString());
    if (!!collateralAdjustmentDocs.length) {
      return collateralAdjustmentDocs.pop().items;
    }
    return [];
  }

  private calculateSummary(collateralAdjustmentItems: ICollateralAdjustmentItem[]): ICollateralAdjustmentSummary {
    const summary: { rowDef: string, amount: number }[] = [];
    const summaryOrder = [
      ECollaterals.INVENTORY,
      ECollaterals.RECEIVABLE,
      ECollaterals.OTHER,
    ];
    const result = Object.keys(ECollaterals).map((equipmentType) => {
      const typeSummary = { rowDef: equipmentType, amount: 0 };
      collateralAdjustmentItems.map((item) => {
        if (item.type === equipmentType) {
          typeSummary.amount = new Decimal(typeSummary.amount).add(item.amount ?? 0).toNumber();
        }
        return typeSummary;
      });
      return typeSummary;
    });
    summaryOrder.forEach((summaryType) => {
      summary.push(...result.filter((r) => r.rowDef === summaryType));
    });
    return summary.reduce((acc, s) => ({ ...acc, [s.rowDef]: s }), {});
  }

}
