/**
 * Background usage reporter — periodically scans `transcript_memory.db` for
 * wake cycles that have not yet been queued into `usage.db`, builds usage
 * reports from stored tool call data, and enqueues them.
 *
 * Semantics:
 *  - `wake_cycles.usage_reported = 0` → needs to be enqueued
 *  - `wake_cycles.usage_reported = 1` → already enqueued into usage.db
 *  - Server delivery state is tracked separately in usage.db
 *
 * If tool_calls_json is NULL or invalid, the cycle is still reported with
 * empty tool calls — the server marks coverage as `missing_tool_calls`.
 */
import { listUnreportedWakeCycles, markWakeCycleUsageReported, markWakeCycleUsageReportError, } from "../transcript/transcript-indexer.js";
import { buildWakeCycleUsageReportFromRecord } from "./usage-report-builder.js";
import { enqueueUsageReport } from "./usage-report-queue.js";
import { logger } from "../../logger.js";
/** Maximum wake cycles to process in a single scan. */
const MAX_CYCLES_PER_SCAN = 100;
export class UsageReporter {
    config;
    timer = null;
    scanIntervalMs = 5 * 60_000; // 5 minutes
    constructor(config) {
        this.config = config;
    }
    /**
     * Start the periodic background scan.
     */
    start() {
        if (this.timer)
            return; // already started
        logger.debug("[usage-reporter] Started (scan interval: 5 minutes)");
        // Run an initial scan shortly after startup to catch any unreported
        // cycles from the previous run.
        this.timer = setTimeout(() => {
            this.tick();
        }, 10_000); // 10 seconds after startup
    }
    /**
     * Stop the periodic scan.
     */
    stop() {
        if (this.timer) {
            clearTimeout(this.timer);
            this.timer = null;
        }
        logger.debug("[usage-reporter] Stopped");
    }
    tick() {
        try {
            this.scanAndReport();
        }
        catch (err) {
            logger.warn(`[usage-reporter] Scan failed: ${err instanceof Error ? err.message : String(err)}`);
        }
        finally {
            // Schedule next scan
            if (this.timer !== null) {
                this.timer = setTimeout(() => {
                    this.tick();
                }, this.scanIntervalMs);
            }
        }
    }
    scanAndReport() {
        let rows;
        try {
            rows = listUnreportedWakeCycles(MAX_CYCLES_PER_SCAN);
        }
        catch (err) {
            logger.warn(`[usage-reporter] Failed to query unreported cycles: ${err instanceof Error ? err.message : String(err)}`);
            return;
        }
        if (rows.length === 0)
            return;
        logger.debug(`[usage-reporter] Found ${rows.length} unreported wake cycle(s)`);
        let enqueued = 0;
        let failed = 0;
        for (const row of rows) {
            try {
                const report = buildWakeCycleUsageReportFromRecord({
                    row,
                    config: this.config,
                });
                enqueueUsageReport(report);
                markWakeCycleUsageReported(row.wake_cycle_id);
                enqueued++;
            }
            catch (err) {
                const errorMsg = err instanceof Error ? err.message : String(err);
                markWakeCycleUsageReportError(row.wake_cycle_id, errorMsg);
                failed++;
                logger.warn(`[usage-reporter] Failed to enqueue usage report for ${row.wake_cycle_id}: ${errorMsg}`);
            }
        }
        if (enqueued > 0) {
            logger.system(`[usage-reporter] Enqueued ${enqueued} usage report(s)${failed > 0 ? `, ${failed} failed` : ""}`);
        }
    }
}
//# sourceMappingURL=usage-reporter.js.map