import { CORE_EVENT_VERSION, } from "./types.js";
const stopReasons = ["stop", "length", "toolUse", "error", "aborted"];
const subagentStatuses = ["running", "success", "error", "aborted"];
const noticeSeverities = ["info", "warn", "error"];
const compactionReasons = ["threshold"];
const compactionOutcomes = ["compacted", "skipped", "aborted", "failed"];
const compactionCutTypes = ["turn-boundary", "split-turn"];
const fail = (message) => ({ ok: false, message });
export function parseCoreEvent(value) {
    const parsed = safeParseCoreEvent(value);
    if (!parsed.ok)
        throw new Error(parsed.message);
    return parsed.value;
}
export function safeParseCoreEvent(value) {
    if (!isRecord(value)) {
        return fail("core event payload must be an object");
    }
    if (typeof value.type !== "string") {
        return fail("core event payload.type must be a string");
    }
    if (!isValidCoreEvent(value, value.type)) {
        return fail("invalid core event payload");
    }
    return { ok: true, value: value };
}
export function parseCoreEventEnvelope(value) {
    const parsed = safeParseCoreEventEnvelope(value);
    if (!parsed.ok)
        throw new Error(parsed.message);
    return parsed.value;
}
export function safeParseCoreEventEnvelope(value) {
    if (!isRecord(value)) {
        return fail("core event envelope must be an object");
    }
    if (!isCoreEventVersion(value.version)) {
        return fail(`unsupported core event version: ${String(value.version)}`);
    }
    const event = safeParseCoreEvent(value.event);
    if (!event.ok) {
        return fail(`invalid core event envelope: ${event.message}`);
    }
    return {
        ok: true,
        value: {
            version: CORE_EVENT_VERSION,
            event: event.value,
        },
    };
}
export function isCoreEventVersion(value) {
    return value === CORE_EVENT_VERSION;
}
function isValidCoreEvent(value, eventType) {
    switch (eventType) {
        case "assistant_start":
            return typeof value.historyEntryId === "string";
        case "assistant_final":
            return typeof value.historyEntryId === "string" && isAssistantMessage(value.message);
        case "assistant_partial":
            return typeof value.historyEntryId === "string" && isAssistantPartialSnapshot(value.snapshot);
        case "notice":
            return isOneOf(value.severity, noticeSeverities) && typeof value.text === "string";
        case "tool_ui":
            return isToolUiEvent(value.uiEvent);
        case "subagent_ui":
            return typeof value.originHistoryEntryId === "string" && isSubagentUiEvent(value.event);
        case "tool_result":
            return typeof value.historyEntryId === "string" && isToolResultMessage(value.message);
        case "compaction_start":
            return isOneOf(value.reason, compactionReasons);
        case "compaction_end":
            return isCompactionEndEvent(value);
        default:
            return false;
    }
}
function isCompactionEndEvent(value) {
    if (!isOneOf(value.reason, compactionReasons) || !isOneOf(value.outcome, compactionOutcomes)) {
        return false;
    }
    switch (value.outcome) {
        case "compacted":
            return value.errorMessage === undefined && isCompactionResult(value.result);
        case "failed":
            return value.result === undefined && typeof value.errorMessage === "string";
        case "skipped":
        case "aborted":
            return value.result === undefined && value.errorMessage === undefined;
    }
}
function isCompactionResult(value) {
    return (isRecord(value) &&
        typeof value.summaryHistoryEntryId === "string" &&
        typeof value.continuationHistoryEntryId === "string" &&
        typeof value.compactionMessage === "string" &&
        isOneOf(value.cutType, compactionCutTypes) &&
        isPositiveInteger(value.retainedMessageCount));
}
function isPositiveInteger(value) {
    return typeof value === "number" && Number.isInteger(value) && value > 0;
}
function isAssistantMessage(value) {
    return (isRecord(value) &&
        value.role === "assistant" &&
        (value.stopReason === undefined || isOneOf(value.stopReason, stopReasons)));
}
function isToolResultMessage(value) {
    return (isRecord(value) &&
        value.role === "toolResult" &&
        typeof value.toolCallId === "string" &&
        typeof value.toolName === "string");
}
function isAssistantPartialSnapshot(value) {
    return (isRecord(value) &&
        typeof value.text === "string" &&
        typeof value.thinking === "string" &&
        typeof value.hasTextStarted === "boolean" &&
        typeof value.hasAnyThinking === "boolean");
}
function isToolUiEvent(value) {
    if (!isRecord(value) || typeof value.type !== "string") {
        return false;
    }
    if (value.type === "tool_pruned") {
        return typeof value.toolCallId === "string" && typeof value.content === "string";
    }
    return typeof value.headerTarget === "string";
}
function isSubagentUiEvent(value) {
    if (!isRecord(value) || typeof value.type !== "string") {
        return false;
    }
    switch (value.type) {
        case "subagent_spawned":
        case "subagent_finished":
            return isSubagentState(value.state);
        case "subagent_progress":
            return (typeof value.id === "string" &&
                typeof value.text === "string" &&
                isFiniteNumber(value.costTotal) &&
                isFiniteNumber(value.turns) &&
                isFiniteNumber(value.toolCalls) &&
                isSubagentUsageSnapshot(value.usage));
        case "subagent_emit_output":
            return typeof value.id === "string" && typeof value.text === "string";
        case "subagent_abort_requested":
            return typeof value.id === "string";
        default:
            return false;
    }
}
function isSubagentState(value) {
    return (isRecord(value) &&
        typeof value.id === "string" &&
        typeof value.name === "string" &&
        typeof value.title === "string" &&
        isOneOf(value.status, subagentStatuses) &&
        isSubagentUsageSnapshot(value.usage));
}
function isSubagentUsageSnapshot(value) {
    return (isRecord(value) &&
        isFiniteNumber(value.input) &&
        isFiniteNumber(value.output) &&
        isFiniteNumber(value.cacheRead) &&
        isFiniteNumber(value.cacheWrite) &&
        isFiniteNumber(value.contextWindowUsageTokens) &&
        isFiniteNumber(value.contextWindow));
}
function isRecord(value) {
    return typeof value === "object" && value !== null && !Array.isArray(value);
}
function isFiniteNumber(value) {
    return typeof value === "number" && Number.isFinite(value);
}
function isOneOf(value, values) {
    return typeof value === "string" && values.includes(value);
}
//# sourceMappingURL=parser.js.map