"use strict";
/**
 * test_story_lifecycle — v1.12.0 lifecycle + writer regression suite.
 *
 * Covers the StoryLifecycle.canTransition matrix and the
 * StoryWriter.updateStoryStatus round-trip through AtomicWriter.
 *
 * Run via: `npm run test:story-lifecycle`.
 */
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 os = __importStar(require("os"));
const path = __importStar(require("path"));
const StoryLifecycle_1 = require("./orchestrator/story/StoryLifecycle");
const StoryWriter_1 = require("./orchestrator/story/StoryWriter");
const StoryParser_1 = require("./orchestrator/story/StoryParser");
function assert(cond, msg) {
    if (!cond)
        throw new Error(`assertion failed: ${msg}`);
}
function mkTmp() {
    return fs.mkdtempSync(path.join(os.tmpdir(), 'storylc-'));
}
function rmTmp(dir) {
    try {
        fs.rmSync(dir, { recursive: true, force: true });
    }
    catch { /* ignore */ }
}
function lifecycleMatrix() {
    // Allowed transitions
    assert((0, StoryLifecycle_1.canTransition)('Draft', 'Ready', 'po').allowed, 'po should be allowed Draft → Ready');
    assert((0, StoryLifecycle_1.canTransition)('Ready', 'InProgress', 'dev').allowed, 'dev should be allowed Ready → InProgress');
    assert((0, StoryLifecycle_1.canTransition)('InProgress', 'InReview', 'dev').allowed, 'dev should be allowed InProgress → InReview');
    assert((0, StoryLifecycle_1.canTransition)('InReview', 'Done', 'qa').allowed, 'qa should be allowed InReview → Done');
    assert((0, StoryLifecycle_1.canTransition)('InReview', 'Done', 'po').allowed, 'po should be allowed InReview → Done');
    assert((0, StoryLifecycle_1.canTransition)('InReview', 'InProgress', 'dev').allowed, 'dev should be allowed InReview → InProgress (reopen)');
    assert((0, StoryLifecycle_1.canTransition)('Draft', 'Ready', 'admin').allowed, 'admin should be allowed any defined transition');
    // Role mismatch
    const denied = (0, StoryLifecycle_1.canTransition)('Draft', 'Ready', 'dev');
    assert(!denied.allowed && /role/i.test(denied.reason || ''), 'dev should be denied Draft → Ready');
    // Undefined transition
    const skip = (0, StoryLifecycle_1.canTransition)('Draft', 'Done', 'po');
    assert(!skip.allowed && /not defined/i.test(skip.reason || ''), 'Draft → Done should not be defined');
    // Same status
    const same = (0, StoryLifecycle_1.canTransition)('Ready', 'Ready', 'po');
    assert(!same.allowed && /already/i.test(same.reason || ''), 'self-transition should be blocked');
    // Unknown status
    const bogus = (0, StoryLifecycle_1.canTransition)('Ready', 'Frobbed', 'po');
    assert(!bogus.allowed && /unknown target status/i.test(bogus.reason || ''), 'bogus target rejected');
    // allowedNextStates
    const fromInReview = (0, StoryLifecycle_1.allowedNextStates)('InReview').sort();
    assert(JSON.stringify(fromInReview) === JSON.stringify(['Done', 'InProgress']), `unexpected next states from InReview: ${fromInReview}`);
    assert((0, StoryLifecycle_1.allowedNextStates)('Done').length === 0, 'no transitions defined out of Done in v1.12');
}
function writerUpdatesStatusAndAppendsChangeLog() {
    const tmp = mkTmp();
    try {
        const fp = path.join(tmp, '9.9.story.md');
        fs.writeFileSync(fp, [
            '# Story 9.9 — synth',
            '',
            '**StoryId:** `9.9`',
            '**Epic:** `epic-x`',
            '**Status:** Ready',
            '',
            '## Description',
            'Body.',
            '',
            '## Change Log',
            '',
            '- 2026-05-01 — @dev (Alice) — Initial.',
        ].join('\n'));
        (0, StoryWriter_1.updateStoryStatus)(fp, 'Ready', 'InProgress', { date: '2026-05-21', author: '@dev (Test)', note: 'kick off.' });
        const content = fs.readFileSync(fp, 'utf-8');
        assert(/\*\*Status:\*\*\s+InProgress/.test(content), 'Status line not updated');
        assert(content.includes('2026-05-21 — @dev (Test) — kick off.'), 'change log entry not appended');
        assert(content.includes('2026-05-01 — @dev (Alice) — Initial.'), 'prior change log entry must survive');
        // Round-trip back through parser.
        const parsed = (0, StoryParser_1.parseStory)(content, fp);
        assert(parsed.value.status === 'InProgress', 'parser sees new status');
        assert(parsed.value.changeLog.length === 2, 'parser sees both change log entries');
    }
    finally {
        rmTmp(tmp);
    }
}
function writerCreatesChangeLogWhenMissing() {
    const tmp = mkTmp();
    try {
        const fp = path.join(tmp, '8.8.story.md');
        fs.writeFileSync(fp, [
            '# Story 8.8',
            '',
            '**StoryId:** `8.8`',
            '**Epic:** `epic-y`',
            '**Status:** Draft',
        ].join('\n'));
        (0, StoryWriter_1.updateStoryStatus)(fp, 'Draft', 'Ready', { date: '2026-05-21', author: '@po (Test)' });
        const content = fs.readFileSync(fp, 'utf-8');
        assert(/\*\*Status:\*\*\s+Ready/.test(content), 'status not updated');
        assert(/## Change Log/.test(content), 'change-log section should be created');
        assert(/Status: Draft → Ready/.test(content), 'default note should mention transition');
    }
    finally {
        rmTmp(tmp);
    }
}
function writerSkipsChangeLogWhenAsked() {
    const tmp = mkTmp();
    try {
        const fp = path.join(tmp, '7.7.story.md');
        fs.writeFileSync(fp, [
            '# Story 7.7',
            '',
            '**StoryId:** `7.7`',
            '**Epic:** `epic-z`',
            '**Status:** Draft',
        ].join('\n'));
        (0, StoryWriter_1.updateStoryStatus)(fp, 'Draft', 'Ready', { appendChangeLog: false });
        const content = fs.readFileSync(fp, 'utf-8');
        assert(/\*\*Status:\*\*\s+Ready/.test(content), 'status not updated');
        assert(!/## Change Log/.test(content), 'change log should NOT have been added');
    }
    finally {
        rmTmp(tmp);
    }
}
function main() {
    lifecycleMatrix();
    writerUpdatesStatusAndAppendsChangeLog();
    writerCreatesChangeLogWhenMissing();
    writerSkipsChangeLogWhenAsked();
    console.log('TEST_STORY_LIFECYCLE_OK');
}
try {
    main();
}
catch (e) {
    console.error('TEST_STORY_LIFECYCLE_FAIL:', e instanceof Error ? e.message : e);
    process.exit(1);
}
