import { applyFast, applyWithDiff, applyWithReceipt, cloneState, createEmptyState, } from "../JoinReducer.js";
import { PatchDiff, mergeDiffs } from "../../types/PatchDiff.js";
import { MaterializePatchSummaryAccumulator, } from "./MaterializePatchSummary.js";
function initialState(base) {
    return base === undefined ? createEmptyState() : cloneState(base);
}
async function reduceWithReceipts(source, state, summary) {
    const receipts = [];
    for await (const entry of source) {
        summary.record(entry);
        const result = applyWithReceipt(state, entry.patch, entry.sha);
        receipts.push(result.receipt);
    }
    return { reduced: { state, receipts }, summary: summary.toSummary() };
}
async function reduceWithDiff(source, state, summary) {
    let diff = PatchDiff.empty();
    for await (const entry of source) {
        summary.record(entry);
        const result = applyWithDiff(state, entry.patch, entry.sha);
        diff = mergeDiffs(diff, result.diff);
    }
    return { reduced: { state, diff }, summary: summary.toSummary() };
}
async function reducePlain(source, state, summary) {
    for await (const entry of source) {
        summary.record(entry);
        applyFast(state, entry.patch, entry.sha);
    }
    return { reduced: { state }, summary: summary.toSummary() };
}
export default class MaterializePatchStreamReducer {
    static async reduce(input) {
        const state = initialState(input.base);
        const summary = new MaterializePatchSummaryAccumulator(input.provenanceBase);
        if (input.options.receipts) {
            return await reduceWithReceipts(input.source, state, summary);
        }
        if (input.options.wantDiff) {
            return await reduceWithDiff(input.source, state, summary);
        }
        return await reducePlain(input.source, state, summary);
    }
}
