import { appendEvent } from "../features/observability/index.js";
import { createRunStore, getActiveRun } from "../features/run-state/index.js";
import { listTeamInbox, loadTeamRuntime, updateTeamMemberStatus } from "../features/team-mode/index.js";
import { sanitizeJson } from "../shared/index.js";
export function createEventHandler(args) {
    const store = createRunStore(args.directory, args.config);
    const reasoningPartIds = new Set();
    return async function eventHandler(input) {
        const active = await getActiveRun(store);
        if (!active)
            return;
        const event = sanitizeOpenCodeEvent(input.event, reasoningPartIds);
        const projected = projectOpenCodeEvent(input.event);
        if (projected) {
            await appendEvent(store, active.run_id, {
                type: projected.type,
                actor: "opencode",
                summary: projected.summary,
                metadata: projected.metadata,
            });
        }
        const teamUpdate = await updateTeamMemberStatusFromEvent(store, active.run_id, input.event);
        if (teamUpdate) {
            await appendEvent(store, active.run_id, {
                type: "team_member_status_from_event",
                actor: "opencode",
                summary: `${teamUpdate.member} -> ${teamUpdate.status} from ${teamUpdate.event_type}`,
                metadata: teamUpdate,
            });
        }
        await appendEvent(store, active.run_id, {
            type: "opencode_event",
            actor: "opencode",
            summary: summarizeEvent(input.event),
            metadata: { event: event },
        });
    };
}
async function updateTeamMemberStatusFromEvent(store, runId, input) {
    if (!isRecord(input))
        return undefined;
    const eventType = stringValue(input.type);
    if (!eventType || !eventType.startsWith("session."))
        return undefined;
    const properties = isRecord(input.properties) ? input.properties : {};
    const sessionID = stringValue(properties.sessionID) ?? stringValue(properties.sessionId);
    if (!sessionID)
        return undefined;
    const runtime = await loadTeamRuntime(store, runId);
    const member = runtime?.members.find((candidate) => candidate.session_id === sessionID);
    if (!member)
        return undefined;
    const statusRecord = isRecord(properties.status) ? properties.status : undefined;
    const openCodeStatus = stringValue(statusRecord?.type) ?? stringValue(properties.status);
    let nextStatus;
    let unreadMessages = 0;
    if (eventType === "session.idle" || openCodeStatus === "idle") {
        unreadMessages = (await listTeamInbox(store, runId, member.name, { includeAcknowledged: false })).length;
        nextStatus = unreadMessages > 0 ? "waiting_on_mailbox" : "idle";
    }
    else if (eventType === "session.error") {
        nextStatus = "failed";
    }
    else if (openCodeStatus === "busy") {
        nextStatus = "active";
    }
    else if (openCodeStatus === "retry") {
        nextStatus = "blocked";
    }
    if (!nextStatus || member.status === nextStatus)
        return undefined;
    await updateTeamMemberStatus(store, runId, member.name, nextStatus);
    return {
        event_type: eventType,
        session_id: sessionID,
        member: member.name,
        previous_status: member.status,
        status: nextStatus,
        opencode_status: openCodeStatus,
        unread_messages: unreadMessages,
    };
}
export function projectOpenCodeEvent(input) {
    if (!isRecord(input))
        return undefined;
    const eventType = typeof input.type === "string" ? input.type : undefined;
    if (!eventType)
        return undefined;
    const properties = isRecord(input.properties) ? input.properties : {};
    const sessionID = stringValue(properties.sessionID) ?? stringValue(properties.sessionId);
    const messageID = stringValue(properties.messageID) ?? stringValue(properties.messageId);
    const part = isRecord(properties.part) ? properties.part : undefined;
    const partType = stringValue(part?.type) ?? stringValue(properties.partType);
    const status = stringValue(properties.status) ?? stringValue(properties.type);
    if (eventType.startsWith("message.")) {
        return {
            type: "opencode_message_activity",
            summary: `${eventType}${partType ? ` ${partType}` : ""}${sessionID ? ` in ${sessionID}` : ""}`,
            metadata: sanitizeJson({
                event_type: eventType,
                session_id: sessionID,
                message_id: messageID,
                part_type: partType,
            }),
        };
    }
    if (eventType.startsWith("session.")) {
        return {
            type: "opencode_session_activity",
            summary: `${eventType}${status ? ` ${status}` : ""}${sessionID ? ` ${sessionID}` : ""}`,
            metadata: sanitizeJson({
                event_type: eventType,
                session_id: sessionID,
                status,
            }),
        };
    }
    return undefined;
}
export function sanitizeOpenCodeEvent(input, reasoningPartIds = new Set()) {
    const event = sanitizeJson(input);
    collectReasoningPartIds(event, reasoningPartIds);
    return redactReasoningPayloads(event, reasoningPartIds);
}
function summarizeEvent(event) {
    if (typeof event === "string")
        return event;
    if (typeof event !== "object" || event === null)
        return typeof event;
    const record = event;
    return String(record.type ?? record.event ?? "OpenCode event");
}
function collectReasoningPartIds(input, ids) {
    if (Array.isArray(input)) {
        for (const item of input)
            collectReasoningPartIds(item, ids);
        return;
    }
    if (!isRecord(input))
        return;
    if (input.type === "reasoning" && typeof input.id === "string")
        ids.add(input.id);
    for (const value of Object.values(input))
        collectReasoningPartIds(value, ids);
}
function redactReasoningPayloads(input, reasoningPartIds) {
    if (Array.isArray(input))
        return input.map((item) => redactReasoningPayloads(item, reasoningPartIds));
    if (!isRecord(input))
        return input;
    const output = {};
    for (const [key, value] of Object.entries(input)) {
        output[key] = redactReasoningPayloads(value, reasoningPartIds);
    }
    if (output.type === "reasoning" && typeof output.text === "string") {
        output.text = "[REDACTED_REASONING]";
    }
    if (output.type === "tool" && isRecord(output.state)) {
        if ("output" in output.state)
            output.state.output = "[REDACTED_TOOL_OUTPUT]";
        if ("metadata" in output.state)
            output.state.metadata = "[REDACTED_TOOL_METADATA]";
    }
    if (output.type === "message.part.delta" && isRecord(output.properties)) {
        const properties = output.properties;
        if (properties.field === "text" && typeof properties.partID === "string" && reasoningPartIds.has(properties.partID)) {
            properties.delta = "[REDACTED_REASONING_DELTA]";
        }
    }
    return output;
}
function isRecord(input) {
    return typeof input === "object" && input !== null;
}
function stringValue(value) {
    return typeof value === "string" && value.length > 0 ? value : undefined;
}
//# sourceMappingURL=event-handler.js.map