import QueryError from "../../errors/QueryError.js";
import { compareEventIds } from "../../utils/EventId.js";
const FACT_CURSOR_CLOSE_FAILURE_CODE = 'E_CHECKPOINT_FACT_CURSOR_CLOSE';
const FACT_CURSOR_CLOSE_FAILURE_REASON = 'non-error-rejection';
export function compareFactEvents(left, right) {
    const eventComparison = compareEventIds(left.eventId, right.eventId);
    if (eventComparison !== 0) {
        return eventComparison;
    }
    return compareText(left.fact.sortKey(), right.fact.sortKey());
}
export function sortedOperationFacts(facts) {
    return Object.freeze([...facts].sort(compareFactEvents));
}
export async function readNextFactCursor(writerId, iterator) {
    const result = await iterator.next();
    if (result.done === true) {
        return null;
    }
    return Object.freeze({ writerId, iterator, current: result.value });
}
export async function closeFactCursors(cursors) {
    let firstError = null;
    for (const cursor of cursors) {
        firstError = await closeFactCursor(cursor, firstError);
    }
    if (firstError !== null) {
        throw firstError;
    }
}
async function closeFactCursor(cursor, firstError) {
    try {
        await cursor.iterator.return?.();
        return firstError;
    }
    catch (error) {
        if (firstError !== null) {
            return firstError;
        }
        return error instanceof Error ? error : cursorCloseFailure();
    }
}
function cursorCloseFailure() {
    return new QueryError('Checkpoint patch fact cursor close failed.', {
        code: FACT_CURSOR_CLOSE_FAILURE_CODE,
        context: { reason: FACT_CURSOR_CLOSE_FAILURE_REASON },
    });
}
export function selectFactCursorIndex(cursors) {
    let selectedIndex = 0;
    let selected = cursors[selectedIndex];
    if (selected === undefined) {
        return -1;
    }
    for (let index = 1; index < cursors.length; index += 1) {
        const candidate = cursors[index];
        if (candidate !== undefined && compareCursor(candidate, selected) < 0) {
            selected = candidate;
            selectedIndex = index;
        }
    }
    return selectedIndex;
}
function compareCursor(left, right) {
    const factComparison = compareFactEvents(left.current, right.current);
    if (factComparison !== 0) {
        return factComparison;
    }
    return compareText(left.writerId, right.writerId);
}
function compareText(left, right) {
    return left < right ? -1 : left > right ? 1 : 0;
}
