/**
 * Processes a list of notifications by adding date headers and a "new items" indicator.
 *
 * @param items - The list of notification items to process. These items must be pre-sorted by their `timestamp` in descending order.
 * @param dateTimeFormatter - A service used to format dates for the date headers.
 * @param lastVisitedTimestamp - The timestamp of the user's last visit. This is used to determine where the "new items" indicator should be placed.
 *
 * @returns An array of processed items, including notifications, date headers, and a "new items" indicator if applicable.
 *
 * @example
 * const processedItems = processNotificationItems(
 *     notifications,
 *     dateTimeFormatter,
 *     new Date('2024-09-01T10:00:00Z')
 * );
 *
 * // Output: [
 * //   { type: 'dateHeader', date: '2024-09-01' },
 * //   { type: 'notification', item: notification1 },
 * //   { type: 'notification', item: notification2 },
 * //   { type: 'newItemIndicator' },
 * //   { type: 'dateHeader', date: '2024-08-31' },
 * //   { type: 'notification', item: notification3 },
 * // ]
 */
export function processNotificationItems(items, dateTimeFormatter, lastVisitedTimestamp) {
    const initialContext = {
        items: items,
        processedItems: [],
        lastVisitedTimestamp: lastVisitedTimestamp,
        dateTimeFormatter: dateTimeFormatter,
        newItemIndicatorInserted: false,
        lastProcessedDate: null,
        hasUnseenNotifications: items.some((item) => lastVisitedTimestamp &&
            new Date(item.timestamp) > lastVisitedTimestamp),
    };
    // Add processors here, in the order they should be executed
    const processors = [
        insertNotifications,
        insertNewItemIndicator,
        insertDateGroups,
    ];
    const finalContext = createPipeline(initialContext, processors);
    return finalContext.processedItems;
}
function createPipeline(initialContext, processors) {
    // eslint-disable-next-line unicorn/no-array-reduce
    return processors.reduce((context, processor) => processor(context), initialContext);
}
/**
 *
 * @param context
 */
export function insertNotifications(context) {
    for (const item of context.items) {
        context.processedItems.push({ type: 'notification', item: item });
    }
    return context;
}
/**
 *
 * @param context
 */
export function insertNewItemIndicator(context) {
    const processedWithIndicator = [];
    let newItemIndicatorInserted = context.newItemIndicatorInserted;
    for (const item of context.processedItems) {
        if (item.type === 'notification' &&
            context.lastVisitedTimestamp &&
            !newItemIndicatorInserted &&
            new Date(item.item.timestamp) <= context.lastVisitedTimestamp &&
            context.hasUnseenNotifications) {
            // Insert the new item indicator before the first old notification
            processedWithIndicator.push({ type: 'newItemIndicator' });
            newItemIndicatorInserted = true;
        }
        // Push the current item to the new array
        processedWithIndicator.push(item);
    }
    context.processedItems = processedWithIndicator;
    context.newItemIndicatorInserted = newItemIndicatorInserted;
    return context;
}
/**
 *
 * @param context
 */
// eslint-disable-next-line sonarjs/cognitive-complexity
export function insertDateGroups(context) {
    const newProcessedItems = [];
    let currentGroup = null;
    let lastProcessedDate = null;
    // Iterate through the notifications in processedItems
    for (const item of context.processedItems) {
        if (item.type === 'notification') {
            const currentTimestamp = new Date(item.item.timestamp);
            const currentDate = context.dateTimeFormatter.format(currentTimestamp, 'date');
            // If the date changes, push the previous group and create a new group
            if (currentDate !== lastProcessedDate) {
                if (currentGroup) {
                    newProcessedItems.push(currentGroup);
                }
                currentGroup = {
                    type: 'group',
                    groupType: 'dateGroup',
                    heading: currentDate,
                    items: [],
                };
                lastProcessedDate = currentDate;
            }
            // Add the notification to the current group
            if (currentGroup) {
                currentGroup.items.push(item);
            }
        }
        else if (item.type === 'newItemIndicator') {
            // Insert the newItemIndicator within the current group if it exists
            if (currentGroup) {
                currentGroup.items.push(item);
            }
            else {
                newProcessedItems.push(item); // Edge case: no group exists, just add the indicator
            }
        }
    }
    // Push the last group, if it exists
    if (currentGroup) {
        newProcessedItems.push(currentGroup);
    }
    // Return updated context with grouped items
    return Object.assign(Object.assign({}, context), { processedItems: newProcessedItems });
}
