import _ from 'lodash';
import mongoose from 'mongoose';

import {
  IInventoryAvailability,
  IInventoryAvailabilityDocument,
  IInventoryAvailabilityResults,
  InventoryAvailabilityModel,
  InventoryAvailabilityPaginators,
} from '../models/InventoryAvailability.model';
import {
  IInventoryAvailabilityItemDocWithInventory,
  InventoryAvailabilityItemModel,
} from '../models/InventoryAvailabilityItem.model';
import { EInventoryAvailabilityResults } from '../enums/inventory-availability-results.enum';
import { ITEMS_PAGINATION } from './collaterals.db';

export const createInventoryAvailability = async (inventoryAvailability: Partial<IInventoryAvailability>): Promise<IInventoryAvailabilityDocument> => {
  const update = _.pick(inventoryAvailability, ['borrowerId', 'filters', 'options']);
  return InventoryAvailabilityModel
    .findOneAndUpdate(
      { bbcDateId: inventoryAvailability.bbcDateId },
      update,
      { upsert: true, new: true }
    )
    .lean();
}

export const getInventoryAvailabilityItems = async (inventoryAvailabilityId: string, paginators: InventoryAvailabilityPaginators): Promise<Partial<IInventoryAvailabilityResults>> => {
  const getMap = {
    [EInventoryAvailabilityResults.UNIQ_ITEMS]: {
      unique: true,
      matched: true,
    },
    [EInventoryAvailabilityResults.NON_UNIQ_ITEMS]: {
      unique: false,
      matched: true,
    },
    [EInventoryAvailabilityResults.NOT_MATCHED_ITEMS]: {
      unique: false,
      matched: false,
    },
  };
  const allItems = await Promise.all(Object.entries(getMap).map(async ([key, settings]) => {
    const items = await InventoryAvailabilityItemModel.aggregate<IInventoryAvailabilityItemDocWithInventory>([
      {
        $match: {
          'inventoryAvailabilityId': new mongoose.Types.ObjectId(inventoryAvailabilityId),
          'unique': settings.unique,
          'matched': settings.matched,
        }
      },
      {
        $sort: {
          order: 1
        }
      },
      ...ITEMS_PAGINATION(paginators[key]),
      {
        $lookup: {
          from: 'inventoryitems',
          localField: 'inventoryId',
          foreignField: '_id',
          as: 'inventory',
        },
      },
      {
        $replaceRoot: {
          newRoot: {
            $mergeObjects: [
              {
                $arrayElemAt: ['$inventory', 0],
              },
              '$$ROOT',
            ],
          },
        },
      },
      {
        $unwind: {
          path: '$inventory',
        },
      },
      {
        $lookup: {
          from: 'bbcsheets',
          localField: 'inventory.bbcSheetId',
          foreignField: '_id',
          as: 'bbcSheet',
        },
      },
      {
        $unwind: {
          path: '$bbcSheet',
        },
      },
      {
        $project: {
          inventory: 0,
        },
      },
    ]);
    const totalItems = await InventoryAvailabilityItemModel.countDocuments(
      {
        'inventoryAvailabilityId': new mongoose.Types.ObjectId(inventoryAvailabilityId),
        'unique': settings.unique,
        'matched': settings.matched,
      },
    );
    return { [key]: { items, totalItems, paginatorOptions: paginators[key] } };
  }, {}));
  return allItems.reduce((acc, group) => ({ ...acc, ...group }), {});
}
