"use strict";
/**
 * test_cron_manager.ts — Story 5.1
 *
 * Asserts the CronManager + parser surface:
 *   1. parseCronExpression validates / rejects expressions
 *   2. CronManager.create/list/pause/resume/remove
 *   3. tick() fires matching jobs and skips paused ones
 *   4. tick() is idempotent within the same minute
 */
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 });
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const os = __importStar(require("os"));
const CronManager_1 = require("./orchestrator/CronManager");
function assertTrue(cond, label) {
    if (!cond)
        throw new Error(`ASSERT_FAILED[${label}]`);
}
async function main() {
    // ── Scenario 1: parser ───────────────────────────────────────────
    assertTrue((0, CronManager_1.parseCronExpression)('* * * * *').ok, 'wildcard accepted');
    assertTrue((0, CronManager_1.parseCronExpression)('0 9 * * 1-5').ok, '9am weekdays accepted');
    assertTrue((0, CronManager_1.parseCronExpression)('*/15 * * * *').ok, 'every 15 min accepted');
    assertTrue(!(0, CronManager_1.parseCronExpression)('').ok, 'empty rejected');
    assertTrue(!(0, CronManager_1.parseCronExpression)('* * * *').ok, '4 fields rejected');
    assertTrue(!(0, CronManager_1.parseCronExpression)('60 * * * *').ok, 'minute=60 rejected');
    assertTrue(!(0, CronManager_1.parseCronExpression)('* 25 * * *').ok, 'hour=25 rejected');
    console.log('[5.1] parser ok ✓');
    // ── Scenario 2: matchesCron sanity ───────────────────────────────
    const f1 = (0, CronManager_1.parseCronExpression)('* * * * *').fields;
    assertTrue((0, CronManager_1.matchesCron)(f1, new Date()), 'wildcard matches now');
    // ── Scenario 3: lifecycle CRUD ──────────────────────────────────
    const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'cron-mgr-'));
    try {
        const cron = new CronManager_1.CronManager({ stateDir: tmp });
        const job = cron.create('job-1', '* * * * *', { mission: 'demo' });
        assertTrue(job.id === 'job-1' && job.status === 'active', 'create returns active');
        assertTrue(cron.list().length === 1, 'list shows 1 job');
        assertTrue(cron.pause('job-1'), 'pause ok');
        assertTrue(cron.list()[0].status === 'paused', 'job paused');
        assertTrue(cron.resume('job-1'), 'resume ok');
        assertTrue(cron.list()[0].status === 'active', 'job active again');
        console.log('[5.1] CRUD ✓');
        // ── Scenario 4: invalid id rejected ─────────────────────────────
        let invalidIdRejected = false;
        try {
            cron.create('Bad ID with space', '* * * * *');
        }
        catch (e) {
            invalidIdRejected = e.code === 'invalid_cron_id';
        }
        assertTrue(invalidIdRejected, 'invalid_cron_id surfaced');
        console.log('[5.1] invalid_cron_id ✓');
        // ── Scenario 5: tick fires matching jobs ─────────────────────────
        const fired = [];
        const executor = {
            execute(j) { fired.push(j.id); },
        };
        const cron2 = new CronManager_1.CronManager({ stateDir: tmp, executor });
        const firedNow = await cron2.tick();
        assertTrue(firedNow.length === 1, `tick fires 1 job (got ${firedNow.length})`);
        assertTrue(fired.length === 1 && fired[0] === 'job-1', 'executor invoked');
        console.log('[5.1] tick fires ✓');
        // ── Scenario 6: tick is idempotent within the same minute ───────
        const firedAgain = await cron2.tick();
        assertTrue(firedAgain.length === 0, 'second tick same minute fires nothing');
        console.log('[5.1] tick idempotent within minute ✓');
        // ── Scenario 7: paused jobs do not fire on a future minute ──────
        cron2.pause('job-1');
        // Bump time by 1 minute via a Date subclass — simulate next-minute tick.
        const future = new Date(Date.now() + 60 * 1000);
        const firedFuture = await cron2.tick(future);
        assertTrue(firedFuture.length === 0, 'paused job does not fire next minute');
        console.log('[5.1] paused jobs do not fire ✓');
        // ── Scenario 8: remove ──────────────────────────────────────────
        assertTrue(cron.remove('job-1'), 'remove ok');
        assertTrue(cron.list().length === 0, 'job removed');
        assertTrue(!cron.remove('job-1'), 'remove returns false on missing');
        console.log('[5.1] remove ✓');
    }
    finally {
        fs.rmSync(tmp, { recursive: true, force: true });
    }
    console.log('TEST_CRON_MANAGER_OK');
}
main().catch((err) => {
    console.error('[cron-manager] FAILED:', err instanceof Error ? err.message : err);
    process.exit(1);
});
