// engine/cost-tracking/ledger.ts — Per-operation cost ledger (SPEC-475)
import { appendFile, readFile, mkdir } from 'node:fs/promises';
import { join, dirname } from 'node:path';
import { hashProjectPath } from '../../storage/base-store.js';
// ---------------------------------------------------------------------------
// Model pricing (USD per token)
// ---------------------------------------------------------------------------
const PRICING = {
    opus: { input: 15 / 1_000_000, output: 75 / 1_000_000 },
    sonnet: { input: 3 / 1_000_000, output: 15 / 1_000_000 },
    haiku: { input: 0.8 / 1_000_000, output: 4 / 1_000_000 },
    unknown: { input: 0, output: 0 },
};
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function getDataDir() {
    return join(process.cwd(), 'data');
}
function getLedgerPath(projectPath) {
    const projectId = hashProjectPath(projectPath);
    return join(getDataDir(), projectId, 'cost-ledger.jsonl');
}
function isPeriodMatch(ts, period) {
    if (period === 'all') {
        return true;
    }
    const entryDate = new Date(ts);
    const now = new Date();
    const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    if (period === 'today') {
        return entryDate >= startOfToday;
    }
    if (period === 'week') {
        const dayOfWeek = now.getDay();
        const startOfWeek = new Date(startOfToday);
        startOfWeek.setDate(startOfToday.getDate() - dayOfWeek);
        return entryDate >= startOfWeek;
    }
    // month
    const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1);
    return entryDate >= startOfMonth;
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Calculate the cost in USD for the given model and token counts.
 */
export function calculateCost(model, tokensInput, tokensOutput) {
    const p = PRICING[model];
    return tokensInput * p.input + tokensOutput * p.output;
}
/**
 * Fire-and-forget. Never blocks the calling tool.
 */
export function writeCostEntry(projectPath, entry) {
    void (async () => {
        try {
            const ledgerPath = getLedgerPath(projectPath);
            await mkdir(dirname(ledgerPath), { recursive: true });
            await appendFile(ledgerPath, JSON.stringify(entry) + '\n', 'utf-8');
        }
        catch {
            /* best-effort — never surface errors to the caller */
        }
    })();
}
/**
 * Read all entries, filter by period, and aggregate into a CostBreakdown.
 */
export async function readBreakdown(projectPath, period, topN = 10) {
    const ledgerPath = getLedgerPath(projectPath);
    let raw;
    try {
        raw = await readFile(ledgerPath, 'utf-8');
    }
    catch {
        raw = '';
    }
    const entries = raw
        .split('\n')
        .filter((line) => line.trim().length > 0)
        .map((line) => {
        try {
            return JSON.parse(line);
        }
        catch {
            return null;
        }
    })
        .filter((e) => e !== null)
        .filter((e) => isPeriodMatch(e.ts, period));
    // Aggregate totals
    let totalCost = 0;
    let totalTokens = 0;
    const byTool = {};
    const byModel = {};
    for (const entry of entries) {
        totalCost += entry.costUsd;
        totalTokens += entry.tokensInput + entry.tokensOutput;
        // By tool
        const toolKey = entry.toolName;
        const existing = byTool[toolKey];
        if (existing !== undefined) {
            existing.cost += entry.costUsd;
            existing.calls += 1;
        }
        else {
            byTool[toolKey] = { cost: entry.costUsd, calls: 1 };
        }
        // By model
        const modelKey = entry.model;
        const existingModel = byModel[modelKey];
        const entryTokens = entry.tokensInput + entry.tokensOutput;
        if (existingModel !== undefined) {
            existingModel.cost += entry.costUsd;
            existingModel.tokens += entryTokens;
        }
        else {
            byModel[modelKey] = { cost: entry.costUsd, tokens: entryTokens };
        }
    }
    // Top N most expensive entries
    const topExpensive = [...entries]
        .sort((a, b) => b.costUsd - a.costUsd)
        .slice(0, topN)
        .map((e) => ({ toolName: e.toolName, cost: e.costUsd, ts: e.ts }));
    return {
        total: { cost: totalCost, tokens: totalTokens, calls: entries.length },
        byTool,
        byModel,
        topExpensive,
        period,
    };
}
//# sourceMappingURL=ledger.js.map