"use strict";
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 () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.maintenanceRegistry = void 0;
const hotmesh_1 = require("@hotmeshio/hotmesh");
const db_1 = require("../../lib/db");
const logger_1 = require("../../lib/logger");
const dbaService = __importStar(require("../dba"));
const CRON_TOPIC = 'lt.maintenance.prune';
const CRON_ID = 'lt-maintenance-nightly';
/**
 * Translate a single maintenance rule into the appropriate dbaService.prune() call.
 */
async function executeRule(rule) {
    switch (true) {
        // Delete stream messages
        case rule.target === 'streams' && rule.action === 'delete':
            await dbaService.prune({
                expire: rule.olderThan,
                streams: true,
                jobs: false,
            });
            break;
        // Delete transient jobs (entity IS NULL)
        case rule.target === 'jobs' && rule.action === 'delete' && rule.hasEntity === false:
            await dbaService.prune({
                expire: rule.olderThan,
                jobs: false,
                streams: false,
                pruneTransient: true,
            });
            break;
        // Strip execution artifacts from entity jobs (keep jdata/udata/jmark/hmark)
        case rule.target === 'jobs' && rule.action === 'prune' && rule.hasEntity === true:
            await dbaService.prune({
                expire: rule.olderThan,
                jobs: false,
                streams: false,
                attributes: true,
                keepHmark: true,
            });
            break;
        // Hard-delete old pruned jobs
        case rule.target === 'jobs' && rule.action === 'delete' && rule.pruned === true:
            await dbaService.prune({
                expire: rule.olderThan,
                jobs: true,
                streams: false,
            });
            break;
        default:
            logger_1.loggerRegistry.warn(`[lt-maintenance] unknown rule, skipping: ${JSON.stringify(rule)}`);
    }
}
/**
 * Singleton registry for automatic database maintenance.
 *
 * Follows the same pattern as telemetryRegistry and eventRegistry:
 * - register(config) — set the maintenance schedule and rules
 * - connect()        — start the Virtual.cron
 * - disconnect()     — interrupt the cron
 * - clear()          — reset (for tests)
 */
class LTMaintenanceRegistry {
    constructor() {
        this._config = null;
        this.connected = false;
    }
    /**
     * Register a maintenance configuration. Call before connect().
     * Replaces any previously registered config.
     */
    register(config) {
        this._config = config;
    }
    /**
     * Start the maintenance cron using Virtual.cron().
     * Idempotent — given the same CRON_ID, restarts won't duplicate.
     */
    async connect() {
        if (this.connected || !this._config)
            return;
        const rules = this._config.rules;
        const schedule = this._config.schedule;
        const connection = (0, db_1.getConnection)();
        await hotmesh_1.Virtual.cron({
            topic: CRON_TOPIC,
            connection,
            callback: async () => {
                logger_1.loggerRegistry.info('[lt-maintenance] starting maintenance cycle...');
                for (const rule of rules) {
                    try {
                        await executeRule(rule);
                    }
                    catch (err) {
                        logger_1.loggerRegistry.error(`[lt-maintenance] rule failed: ${JSON.stringify(rule)} ${err?.message}`);
                    }
                }
                logger_1.loggerRegistry.info('[lt-maintenance] maintenance cycle complete.');
            },
            args: [],
            options: {
                id: CRON_ID,
                interval: schedule,
            },
        });
        this.connected = true;
        logger_1.loggerRegistry.info(`[lt-maintenance] cron started (schedule: ${schedule})`);
    }
    /**
     * Disconnect on graceful shutdown. Stops consuming but leaves the cron
     * row alive — it's a durable job shared across the fleet. Another
     * container (or this one on restart) will continue servicing it.
     */
    async disconnect() {
        this.connected = false;
    }
    /**
     * Remove config and reset state. Used in tests.
     */
    clear() {
        this._config = null;
        this.connected = false;
    }
    /**
     * Check if a config is registered.
     */
    get hasConfig() {
        return this._config !== null;
    }
    /**
     * Get the current config.
     */
    get config() {
        return this._config;
    }
}
/** Singleton maintenance registry */
exports.maintenanceRegistry = new LTMaintenanceRegistry();
