/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
export class BudgetAccumulator {
    totalTokens = 0;
    totalCostCents = 0;
    retryCount = 0;
    startTime;
    phase;
    envelope;
    constructor(phase, envelope) {
        this.phase = phase;
        this.envelope = envelope;
        this.startTime = Date.now();
    }
    accumulate(tokens, cost, retryCount) {
        this.totalTokens += tokens;
        this.totalCostCents += cost;
        this.retryCount = retryCount;
    }
    isExceeded() {
        const usage = this.currentUsage();
        const result = checkBudget(this.envelope, usage);
        return { exceeded: !result.allowed, reasons: result.exceeded };
    }
    toReport() {
        const usage = this.currentUsage();
        const result = checkBudget(this.envelope, usage);
        const utilizationPct = {};
        if (this.envelope.maxTokens !== undefined) {
            utilizationPct.tokens = pct(this.totalTokens, this.envelope.maxTokens);
        }
        if (this.envelope.maxCostCents !== undefined) {
            utilizationPct.cost = pct(this.totalCostCents, this.envelope.maxCostCents);
        }
        if (this.envelope.maxRetries !== undefined) {
            utilizationPct.retries = pct(this.retryCount, this.envelope.maxRetries);
        }
        if (this.envelope.maxMinutes !== undefined) {
            utilizationPct.time = pct(this.elapsedMinutes(), this.envelope.maxMinutes);
        }
        return {
            phase: this.phase,
            envelope: this.envelope,
            usage,
            utilizationPct,
            exceeded: !result.allowed,
            exceededReasons: result.exceeded,
        };
    }
    resetTimer() {
        this.startTime = Date.now();
    }
    currentUsage() {
        return {
            tokens: this.totalTokens,
            costCents: this.totalCostCents,
            retries: this.retryCount,
            elapsedMinutes: this.elapsedMinutes(),
        };
    }
    elapsedMinutes() {
        return (Date.now() - this.startTime) / 60_000;
    }
}
function pct(value, max) {
    if (max === 0)
        return value > 0 ? Infinity : 0;
    return Math.round((value / max) * 100);
}
export function resolveBudgetEnvelope(envelopes, phase) {
    if (!envelopes || envelopes.length === 0)
        return null;
    const specific = envelopes.find((e) => e.phase === phase);
    if (specific)
        return specific;
    const global = envelopes.find((e) => !e.phase);
    return global ?? null;
}
export function checkBudget(envelope, usage) {
    if (!envelope)
        return { allowed: true, exceeded: [], envelope: {} };
    const exceeded = [];
    if (envelope.maxTokens !== undefined && usage.tokens !== undefined && usage.tokens > envelope.maxTokens) {
        exceeded.push(`tokens: ${usage.tokens}/${envelope.maxTokens}`);
    }
    if (envelope.maxCostCents !== undefined && usage.costCents !== undefined && usage.costCents > envelope.maxCostCents) {
        exceeded.push(`cost: ${usage.costCents}¢/${envelope.maxCostCents}¢`);
    }
    if (envelope.maxRetries !== undefined && usage.retries !== undefined && usage.retries > envelope.maxRetries) {
        exceeded.push(`retries: ${usage.retries}/${envelope.maxRetries}`);
    }
    if (envelope.maxMinutes !== undefined &&
        usage.elapsedMinutes !== undefined &&
        usage.elapsedMinutes > envelope.maxMinutes) {
        exceeded.push(`time: ${usage.elapsedMinutes}m/${envelope.maxMinutes}m`);
    }
    return { allowed: exceeded.length === 0, exceeded, envelope };
}
//# sourceMappingURL=budget-envelope.js.map