// ─────────────────────────────────────────────────────────────────────────────
// Built-in Middleware
// ─────────────────────────────────────────────────────────────────────────────
/** Enforces token budget limits before execution */
export const TokenBudgetMiddleware = {
    name: 'token-budget',
    priority: 10,
    before(ctx) {
        const budget = ctx.meta.tokenBudget ?? 0;
        const used = ctx.meta.tokensUsed ?? 0;
        if (budget > 0 && used >= budget) {
            ctx.meta.shortCircuitResult = {
                content: [{ type: 'text', text: `Token budget exhausted (${used}/${budget}). Operation skipped.` }],
            };
        }
        ctx.meta.middlewareTokenCheckAt = Date.now();
    },
};
/** Tracks feature usage and timing via telemetry */
export const TelemetryMiddleware = {
    name: 'telemetry',
    priority: 20,
    before(ctx) {
        ctx.meta._telemetryStartMs = Date.now();
    },
    after(ctx) {
        const durationMs = Date.now() - (ctx.meta._telemetryStartMs ?? Date.now());
        ctx.meta.telemetryDurationMs = durationMs;
        // Actual telemetry.trackFeatureUsage() is called by the adapter after middleware completes
    },
    onError(ctx) {
        ctx.meta.telemetryErrorAt = Date.now();
    },
};
/** Auto-injects project memories and scopes stored memories */
export const MemoryMiddleware = {
    name: 'memory',
    priority: 30,
    before(ctx) {
        // Flag that memory injection should happen for this tool call
        if (ctx.projectHash) {
            ctx.meta.memoryProjectHash = ctx.projectHash;
            ctx.meta.memoryInjectionRequested = true;
        }
    },
    after(ctx) {
        // Track memory interactions for session DNA
        if (ctx.meta.memoriesRecalled) {
            ctx.meta.totalMemoriesRecalled = (ctx.meta.totalMemoriesRecalled ?? 0) + 1;
        }
    },
};
/** Mindkit safety check before file modifications */
export const GuardrailsMiddleware = {
    name: 'guardrails',
    priority: 40,
    before(ctx) {
        const destructiveTools = ['nexus_orchestrate', 'nexus_plan_execution', 'nexus_spawn_workers'];
        if (destructiveTools.includes(ctx.toolName)) {
            ctx.meta.guardrailsCheckRequired = true;
        }
    },
};
/** Estimates and logs cost per operation */
export const CostMiddleware = {
    name: 'cost',
    priority: 50,
    after(ctx, result) {
        const tokensSaved = ctx.meta.tokensSaved ?? 0;
        // Estimate cost based on token usage (Haiku rate: $0.25/1M input, $1.25/1M output)
        const estimatedTokens = result.content.reduce((sum, c) => sum + (c.text?.length ?? 0) / 4, 0);
        ctx.meta.estimatedCostUsd = estimatedTokens * 0.00000125; // output token rate
        ctx.meta.estimatedSavingsUsd = tokensSaved * 0.00000025; // input token rate saved
    },
};
/** Create a pipeline with all built-in middleware pre-registered */
export function createDefaultPipeline() {
    const pipeline = new MiddlewarePipeline();
    pipeline.register(TokenBudgetMiddleware);
    pipeline.register(TelemetryMiddleware);
    pipeline.register(MemoryMiddleware);
    pipeline.register(GuardrailsMiddleware);
    pipeline.register(CostMiddleware);
    return pipeline;
}
// ─────────────────────────────────────────────────────────────────────────────
// Pipeline Core
// ─────────────────────────────────────────────────────────────────────────────
/** Hard deadline for the full pipeline (including all middleware before/after hooks). */
const PIPELINE_HARD_DEADLINE_MS = 120_000;
export class MiddlewarePipeline {
    chain = [];
    /** Override for tests — set before calling execute(). */
    deadlineMs = PIPELINE_HARD_DEADLINE_MS;
    register(middleware) {
        this.chain.push(middleware);
        this.chain.sort((a, b) => a.priority - b.priority);
    }
    async execute(ctx, handler) {
        let deadlineHandle;
        const deadlinePromise = new Promise((_, reject) => {
            deadlineHandle = setTimeout(() => reject(new Error('__nexus_pipeline_timeout__')), this.deadlineMs);
        });
        try {
            const result = await Promise.race([
                this._run(ctx, handler),
                deadlinePromise,
            ]);
            return result;
        }
        finally {
            clearTimeout(deadlineHandle);
        }
    }
    async _run(ctx, handler) {
        const applied = [];
        try {
            let shortCircuitResult;
            for (const middleware of this.chain) {
                await middleware.before?.(ctx);
                applied.push(middleware);
                if (ctx.meta.shortCircuitResult) {
                    shortCircuitResult = ctx.meta.shortCircuitResult;
                    break;
                }
            }
            const result = shortCircuitResult ?? await handler();
            for (const middleware of [...applied].reverse()) {
                await middleware.after?.(ctx, result);
            }
            return result;
        }
        catch (error) {
            for (const middleware of [...applied].reverse()) {
                await middleware.onError?.(ctx, error);
            }
            throw error;
        }
    }
}
