import { gitShowText } from "./git-io.js";
import { resolveSnapshotContentRelativePath, resolveSnapshotMetaRelativePath } from "./layout.js";
import { readEventSegmentsJsonl, readTaskStateBranchLayout } from "./read-branch-layout.js";
import { taskVersionMapFromProjection } from "./publish-task-state-events.js";
import { projectionFromSnapshotContent, replayTailFromSnapshot } from "./snapshot-projection.js";
import { validateTaskStateGitSnapshotMeta } from "./validate-snapshot-meta.js";
import { admitTaskStateEventStream } from "../task-state-events/event-admission.js";
import { admitCanonicalStateEventStream } from "../task-state-events/canonical-event-admission.js";
import { isTaskStateEvent } from "../task-state-events/canonical-state-events.js";
import { replayTaskStateEvents } from "../task-state-events/event-applier.js";
import { createEmptyPlanningStateProjection, replayPlanningStateEvents } from "../task-state-events/planning-event-applier.js";
import { isPlanningStateEventKind } from "../task-state-events/planning-event-payloads.js";
function readSnapshotContent(workspacePath, ref, snapshotId) {
    const metaText = gitShowText(workspacePath, ref, resolveSnapshotMetaRelativePath(snapshotId));
    const contentText = gitShowText(workspacePath, ref, resolveSnapshotContentRelativePath(snapshotId));
    if (!metaText || !contentText) {
        return { ok: false };
    }
    const metaParsed = validateTaskStateGitSnapshotMeta(JSON.parse(metaText));
    if (!metaParsed.ok) {
        return { ok: false };
    }
    return {
        ok: true,
        content: JSON.parse(contentText),
        throughSequence: metaParsed.data.throughSequence
    };
}
/** Replay planning.* events from the full remote JSONL (not snapshot tail only). */
export function replayPlanningProjectionFromRawEvents(rawEvents) {
    const planningEvents = rawEvents.filter((event) => {
        return (event !== null &&
            typeof event === "object" &&
            !Array.isArray(event) &&
            typeof event.kind === "string" &&
            isPlanningStateEventKind(String(event.kind)));
    });
    if (planningEvents.length === 0) {
        return createEmptyPlanningStateProjection();
    }
    const replayed = replayPlanningStateEvents(planningEvents);
    return replayed.ok ? replayed.projection : createEmptyPlanningStateProjection();
}
/** Admit remote JSONL events; lifecycle events require the bootstrap snapshot as replay seed. */
export function admitRemoteEventStream(workspacePath, ref, manifest, rawEvents) {
    const snapshotId = manifest.head.latestSnapshotId;
    if (!snapshotId) {
        const admitted = admitCanonicalStateEventStream(rawEvents, {
            initialPlanningProjection: replayPlanningProjectionFromRawEvents([])
        });
        if (!admitted.ok) {
            return {
                ok: false,
                error: {
                    code: admitted.error.code === "workspace-revision-mismatch" ? "replay-conflict" : admitted.error.code,
                    message: admitted.error.message,
                    details: admitted.error.details
                }
            };
        }
        return { ok: true, events: admitted.events };
    }
    const snapshotRead = readSnapshotContent(workspacePath, ref, snapshotId);
    if (!snapshotRead.ok) {
        return {
            ok: false,
            error: {
                code: "schema-validation-failed",
                message: `snapshot '${snapshotId}' is missing or invalid on ${ref}`
            }
        };
    }
    const throughSequence = snapshotRead.throughSequence;
    const historicalEvents = rawEvents.filter((event) => {
        return (event !== null &&
            typeof event === "object" &&
            !Array.isArray(event) &&
            typeof event.sequence === "number" &&
            event.sequence <= throughSequence);
    });
    const tailEvents = rawEvents.filter((event) => {
        return (event !== null &&
            typeof event === "object" &&
            !Array.isArray(event) &&
            typeof event.sequence === "number" &&
            event.sequence > throughSequence);
    });
    const admitted = admitCanonicalStateEventStream(tailEvents, {
        initialTaskProjection: projectionFromSnapshotContent(snapshotRead.content),
        initialPlanningProjection: replayPlanningProjectionFromRawEvents(historicalEvents)
    });
    if (!admitted.ok) {
        return {
            ok: false,
            error: {
                code: admitted.error.code === "workspace-revision-mismatch" ? "replay-conflict" : admitted.error.code,
                message: admitted.error.message,
                details: admitted.error.details
            }
        };
    }
    return { ok: true, events: admitted.events };
}
export function readRemoteSnapshotProjection(workspacePath, ref, tipSha) {
    const layoutRead = readTaskStateBranchLayout(workspacePath, ref, tipSha);
    if (!layoutRead.ok) {
        return null;
    }
    const segmentPaths = layoutRead.layout.eventSegmentPaths;
    const eventsRead = readEventSegmentsJsonl(workspacePath, ref, segmentPaths);
    const rawEvents = eventsRead.ok && eventsRead.lines.length > 0
        ? eventsRead.lines.map((line) => JSON.parse(line))
        : [];
    const snapshotId = layoutRead.layout.manifest.head.latestSnapshotId;
    if (!snapshotId) {
        const admitted = admitTaskStateEventStream(rawEvents);
        const events = admitted.ok ? admitted.events : [];
        if (events.length === 0) {
            return null;
        }
        const replayed = replayTaskStateEvents(events);
        return replayed.ok ? replayed.result.projection : null;
    }
    const snapshotRead = readSnapshotContent(workspacePath, ref, snapshotId);
    if (!snapshotRead.ok) {
        return null;
    }
    const admitted = admitRemoteEventStream(workspacePath, ref, layoutRead.layout.manifest, rawEvents);
    const events = admitted.ok ? admitted.events : [];
    const tailReplay = replayTailFromSnapshot({
        snapshot: snapshotRead.content,
        throughSequence: snapshotRead.throughSequence,
        tailEvents: events.filter(isTaskStateEvent)
    });
    return tailReplay.ok ? tailReplay.projection : null;
}
export function readRemoteTaskVersionMap(workspacePath, ref, tipSha) {
    const projection = readRemoteSnapshotProjection(workspacePath, ref, tipSha);
    if (!projection) {
        return new Map();
    }
    return taskVersionMapFromProjection(projection);
}
export function expectedVersionsForPublish(_storeVersions, remoteVersions, taskIds) {
    const out = {};
    for (const taskId of taskIds) {
        const remote = remoteVersions.get(taskId);
        out[taskId] = remote !== undefined ? remote : 0;
    }
    return out;
}
