"use strict";
/**
 * Persistent Disk Cache for Usage Data
 *
 * Caches aggregated usage data to disk to avoid re-parsing 6000+ JSONL files
 * on every dashboard startup. Uses TTL-based invalidation with stale-while-revalidate.
 *
 * Cache location: ~/.ccs/cache/usage.json
 * Default TTL: 5 minutes (configurable)
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.clearDiskCache = exports.getCacheAge = exports.writeDiskCache = exports.isDiskCacheStale = exports.isDiskCacheFresh = exports.readDiskCache = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const ui_1 = require("../../utils/ui");
const config_loader_facade_1 = require("../../config/config-loader-facade");
// Cache configuration
function getCacheDir() {
    return path.join((0, config_loader_facade_1.getCcsDir)(), 'cache');
}
function getCacheFile() {
    return path.join(getCacheDir(), 'usage.json');
}
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
const STALE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days (max age for stale data)
// Current cache version - increment to invalidate old caches
// v1: Initial cache format (daily, monthly, session)
// v2: Added multi-instance aggregation
// v3: Added hourly data to cache
// v4: Pricing fix for Claude 4.6 models (invalidate stale costs)
const CACHE_VERSION = 4;
/**
 * Ensure ~/.ccs/cache directory exists
 */
function ensureCacheDir() {
    const dir = getCacheDir();
    if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
    }
}
/**
 * Read usage data from disk cache
 * Returns null if cache is missing, corrupted, or has incompatible version
 * NOTE: Does NOT reject based on age - caller handles staleness via SWR pattern
 */
function readDiskCache() {
    try {
        const cacheFile = getCacheFile();
        if (!fs.existsSync(cacheFile)) {
            return null;
        }
        const data = fs.readFileSync(cacheFile, 'utf-8');
        const cache = JSON.parse(data);
        // Version check - invalidate if schema changed
        if (cache.version !== CACHE_VERSION) {
            console.log((0, ui_1.info)('Cache version mismatch, will refresh'));
            return null;
        }
        // Always return cache regardless of age - SWR pattern handles staleness
        return cache;
    }
    catch (err) {
        // Cache corrupted or unreadable - treat as miss
        console.log((0, ui_1.info)('Cache read failed, will refresh:') + ` ${err.message}`);
        return null;
    }
}
exports.readDiskCache = readDiskCache;
/**
 * Check if disk cache is fresh (within TTL)
 */
function isDiskCacheFresh(cache) {
    if (!cache)
        return false;
    const age = Date.now() - cache.timestamp;
    return age < CACHE_TTL_MS;
}
exports.isDiskCacheFresh = isDiskCacheFresh;
/**
 * Check if disk cache is stale but usable (between TTL and STALE_TTL)
 */
function isDiskCacheStale(cache) {
    if (!cache)
        return false;
    const age = Date.now() - cache.timestamp;
    return age >= CACHE_TTL_MS && age < STALE_TTL_MS;
}
exports.isDiskCacheStale = isDiskCacheStale;
/**
 * Write usage data to disk cache
 */
function writeDiskCache(daily, hourly, monthly, session) {
    try {
        ensureCacheDir();
        const cache = {
            version: CACHE_VERSION,
            timestamp: Date.now(),
            daily,
            hourly,
            monthly,
            session,
        };
        // Write atomically using temp file + rename
        const cacheFile = getCacheFile();
        const tempFile = cacheFile + '.tmp';
        fs.writeFileSync(tempFile, JSON.stringify(cache), 'utf-8');
        fs.renameSync(tempFile, cacheFile);
        console.log((0, ui_1.ok)('Disk cache updated'));
    }
    catch (err) {
        // Non-fatal - we can still serve from memory
        console.log((0, ui_1.warn)('Failed to write disk cache:') + ` ${err.message}`);
    }
}
exports.writeDiskCache = writeDiskCache;
/**
 * Get cache age in human-readable format
 */
function getCacheAge(cache) {
    if (!cache)
        return 'never';
    const age = Date.now() - cache.timestamp;
    const seconds = Math.floor(age / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);
    if (hours > 0)
        return `${hours}h ${minutes % 60}m ago`;
    if (minutes > 0)
        return `${minutes}m ${seconds % 60}s ago`;
    return `${seconds}s ago`;
}
exports.getCacheAge = getCacheAge;
/**
 * Delete disk cache (for manual refresh)
 */
function clearDiskCache() {
    try {
        const cacheFile = getCacheFile();
        if (fs.existsSync(cacheFile)) {
            fs.unlinkSync(cacheFile);
            console.log((0, ui_1.ok)('Disk cache cleared'));
        }
    }
    catch (err) {
        console.log((0, ui_1.warn)('Failed to clear disk cache:') + ` ${err.message}`);
    }
}
exports.clearDiskCache = clearDiskCache;
//# sourceMappingURL=disk-cache.js.map