"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 });
const outcome_engine_1 = require("../../walls/03-knowledge/decisions/outcome-engine");
const outcome_store_1 = require("../../walls/06-memory/stores/outcome-store");
const outcome_types_1 = require("../../walls/06-memory/stores/outcome-types");
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
function tmpDir() {
    const dir = path.join(require('os').tmpdir(), `oc-${Date.now()}`);
    fs.mkdirSync(dir, { recursive: true });
    return dir;
}
function makeEngine(tmp) {
    const store = new outcome_store_1.OutcomeStore(tmp);
    const engine = new outcome_engine_1.OutcomeEngine(store);
    return { engine, store };
}
const CATEGORIES = [
    'variable_declaration', 'function_style', 'quote_style', 'import_style',
    'naming_convention', 'string_style', 'error_handling', 'security',
    'testing', 'performance', 'async_style', 'type_style',
];
const LANGUAGES = ['typescript', 'javascript', 'python', 'go', 'rust'];
const EVENT_TYPES = [
    'PATTERN_USED', 'PATTERN_ACCEPTED', 'PATTERN_REJECTED',
    'PATTERN_SUCCESS', 'PATTERN_FAILURE', 'PATTERN_MODIFIED', 'PATTERN_REPLACED',
];
function randomItem(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}
function seedPatterns(engine, count, baseTime) {
    const ids = [];
    for (let i = 0; i < count; i++) {
        const pid = `p_${i}_${Math.random().toString(36).slice(2, 8)}`;
        ids.push(pid);
        const cat = CATEGORIES[i % CATEGORIES.length];
        const lang = LANGUAGES[i % LANGUAGES.length];
        const event = (0, outcome_types_1.makeEvent)(pid, 'PATTERN_USED', {
            language: lang, category: cat, timestamp: baseTime + i,
        });
        engine.recordEvent(event);
    }
    return ids;
}
function seedOutcomes(engine, patternIds, count, baseTime) {
    for (let i = 0; i < count; i++) {
        const pid = patternIds[i % patternIds.length];
        const type = randomItem(EVENT_TYPES);
        const cat = CATEGORIES[i % CATEGORIES.length];
        const lang = LANGUAGES[i % LANGUAGES.length];
        const event = (0, outcome_types_1.makeEvent)(pid, type, {
            language: lang,
            category: cat,
            timestamp: baseTime + i * 1000 + Math.floor(Math.random() * 500),
            context: `test-${i}`,
            duration: 100 + Math.floor(Math.random() * 4900),
            result: type === 'PATTERN_SUCCESS' ? 'passed' : undefined,
            failureType: type === 'PATTERN_FAILURE' ? 'runtime_error' : undefined,
            failureReason: type === 'PATTERN_FAILURE' ? 'test failure' : undefined,
        });
        engine.recordEvent(event);
    }
}
describe('Chapter 3 — Outcome Engine', () => {
    let tmp;
    let engine;
    let store;
    beforeEach(() => {
        tmp = tmpDir();
        const created = makeEngine(tmp);
        engine = created.engine;
        store = created.store;
    });
    afterEach(() => {
        fs.rmSync(tmp, { recursive: true, force: true });
    });
    test('recordEvent stores event and creates summary', () => {
        const event = (0, outcome_types_1.makeEvent)('p1', 'PATTERN_USED', { language: 'typescript', category: 'variable_declaration' });
        const summary = engine.recordEvent(event);
        expect(summary.patternId).toBe('p1');
        expect(summary.usageCount).toBe(1);
        expect(store.getEventCount()).toBe(1);
    });
    test('multiple events accumulate correctly', () => {
        engine.recordEvent((0, outcome_types_1.makeEvent)('p1', 'PATTERN_USED'));
        engine.recordEvent((0, outcome_types_1.makeEvent)('p1', 'PATTERN_SUCCESS'));
        engine.recordEvent((0, outcome_types_1.makeEvent)('p1', 'PATTERN_FAILURE'));
        engine.recordEvent((0, outcome_types_1.makeEvent)('p1', 'PATTERN_ACCEPTED'));
        engine.recordEvent((0, outcome_types_1.makeEvent)('p1', 'PATTERN_REJECTED'));
        const summary = engine.getSummary('p1');
        expect(summary.usageCount).toBe(5);
        expect(summary.successCount).toBe(1);
        expect(summary.failureCount).toBe(1);
        expect(summary.acceptanceCount).toBe(1);
        expect(summary.rejectionCount).toBe(1);
    });
    test('confidence is evidence-based between 0-1', () => {
        for (let i = 0; i < 10; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)('p_high', 'PATTERN_SUCCESS'));
        }
        const high = engine.getSummary('p_high');
        expect(high.confidence).toBeGreaterThan(0.8);
        for (let i = 0; i < 10; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)('p_low', 'PATTERN_FAILURE'));
        }
        const low = engine.getSummary('p_low');
        expect(low.confidence).toBeLessThan(0.3);
    });
    test('trend classifies correctly', () => {
        const pid = 'p_trend';
        const base = Date.now() - 1000000;
        for (let i = 0; i < 5; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_SUCCESS', { timestamp: base + i * 1000 }));
        }
        for (let i = 0; i < 5; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_FAILURE', { timestamp: base + 5000 + i * 1000 }));
        }
        for (let i = 0; i < 10; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_SUCCESS', { timestamp: base + 20000 + i * 1000 }));
        }
        let s = engine.getSummary(pid);
        expect(s.trend).toBe('rising');
        for (let i = 0; i < 10; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_FAILURE', { timestamp: base + 40000 + i * 1000 }));
        }
        s = engine.getSummary(pid);
        expect(s.trend).toBe('declining');
    });
    test('health score is 0-100', () => {
        for (let i = 0; i < 50; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)('p_good', 'PATTERN_SUCCESS'));
        }
        const good = engine.getSummary('p_good');
        expect(good.health).toBeGreaterThan(70);
        for (let i = 0; i < 50; i++) {
            engine.recordEvent((0, outcome_types_1.makeEvent)('p_bad', 'PATTERN_FAILURE'));
        }
        const bad = engine.getSummary('p_bad');
        expect(bad.health).toBeLessThan(40);
    });
    test('leaderboard generates all 6 categories', () => {
        for (let i = 0; i < 10; i++) {
            const pid = `p_lb_${i}`;
            for (let j = 0; j < 10; j++) {
                const type = j < 7 ? 'PATTERN_SUCCESS' : 'PATTERN_FAILURE';
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, type));
            }
        }
        const lb = engine.generateLeaderboard();
        expect(lb.mostSuccessful.length).toBeGreaterThan(0);
        expect(lb.mostReliable.length).toBeGreaterThan(0);
        expect(lb.mostAccepted.length).toBeGreaterThan(0);
        expect(lb.fastestGrowing.length).toBeGreaterThan(0);
        expect(lb.mostFailed.length).toBeGreaterThan(0);
        expect(lb.mostRejected.length).toBeGreaterThan(0);
        expect(lb.generatedAt).toBeGreaterThan(0);
    });
    test('summaries persist after save+reload', () => {
        engine.recordEvent((0, outcome_types_1.makeEvent)('p_persist', 'PATTERN_USED'));
        engine.recordEvent((0, outcome_types_1.makeEvent)('p_persist', 'PATTERN_SUCCESS'));
        engine.save();
        const store2 = new outcome_store_1.OutcomeStore(tmp);
        const engine2 = new outcome_engine_1.OutcomeEngine(store2);
        const s = engine2.getSummary('p_persist');
        expect(s.usageCount).toBe(2);
        expect(s.successCount).toBe(1);
        expect(s.confidence).toBeGreaterThan(0);
        expect(s.health).toBeGreaterThan(0);
    });
    test('100 patterns, 1000 outcomes', () => {
        const base = Date.now() - 1000000;
        const ids = seedPatterns(engine, 100, base);
        expect(store.getEventCount()).toBe(100);
        seedOutcomes(engine, ids, 900, base + 1000);
        expect(store.getEventCount()).toBe(1000);
        const summaries = engine.getAllSummaries();
        expect(summaries.length).toBe(100);
        for (const s of summaries) {
            expect(s.usageCount).toBeGreaterThanOrEqual(1);
            expect(s.confidence).toBeGreaterThanOrEqual(0);
            expect(s.confidence).toBeLessThanOrEqual(1);
            expect(s.health).toBeGreaterThanOrEqual(0);
            expect(s.health).toBeLessThanOrEqual(100);
            expect(['rising', 'stable', 'declining', 'dead']).toContain(s.trend);
        }
        const lb = engine.generateLeaderboard();
        expect(lb.mostSuccessful.length).toBe(10);
    });
    test('10000 outcomes', () => {
        const base = Date.now() - 5000000;
        const ids = [];
        for (let i = 0; i < 200; i++) {
            ids.push(`p_scale_${i}`);
            engine.recordEvent((0, outcome_types_1.makeEvent)(ids[i], 'PATTERN_USED', {
                language: randomItem(LANGUAGES),
                category: randomItem(CATEGORIES),
                timestamp: base + i,
            }));
        }
        for (let i = 0; i < 9800; i++) {
            const pid = ids[i % ids.length];
            engine.recordEvent((0, outcome_types_1.makeEvent)(pid, randomItem(EVENT_TYPES), {
                timestamp: base + 1000 + i,
                language: randomItem(LANGUAGES),
                category: randomItem(CATEGORIES),
            }));
        }
        expect(store.getEventCount()).toBe(10000);
        const summaries = engine.getAllSummaries();
        expect(summaries.length).toBe(200);
        const lb = engine.generateLeaderboard();
        expect(lb.mostSuccessful.length).toBe(10);
        engine.save();
        const store2 = new outcome_store_1.OutcomeStore(tmp);
        const engine2 = new outcome_engine_1.OutcomeEngine(store2);
        expect(store2.getEventCount()).toBe(10000);
        expect(engine2.getAllSummaries().length).toBe(200);
    });
    test('SIMULATION: rankings, confidence, trend, health all evolve', () => {
        const base = Date.now() - 2000000;
        const ids = [];
        for (let i = 0; i < 100; i++) {
            ids.push(`p_sim_${i}`);
            engine.recordEvent((0, outcome_types_1.makeEvent)(ids[i], 'PATTERN_USED', { timestamp: base + i }));
        }
        for (let i = 0; i < 50; i++) {
            const pid = ids[i];
            for (let j = 0; j < 5; j++) {
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_FAILURE', { timestamp: base + 1000 + j * 1000 }));
            }
            for (let j = 0; j < 15; j++) {
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_SUCCESS', { timestamp: base + 7000 + j * 1000 }));
            }
        }
        for (let i = 50; i < 80; i++) {
            const pid = ids[i];
            for (let j = 0; j < 10; j++) {
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_SUCCESS', { timestamp: base + 1000 + j * 2000 }));
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_FAILURE', { timestamp: base + 1000 + j * 2000 + 1000 }));
            }
        }
        for (let i = 80; i < 100; i++) {
            const pid = ids[i];
            for (let j = 0; j < 5; j++) {
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_SUCCESS', { timestamp: base + 1000 + j * 1000 }));
            }
            for (let j = 0; j < 15; j++) {
                engine.recordEvent((0, outcome_types_1.makeEvent)(pid, 'PATTERN_FAILURE', { timestamp: base + 7000 + j * 1000 }));
            }
        }
        const summaries = engine.getAllSummaries();
        const confidences = summaries.map(s => s.confidence);
        const healths = summaries.map(s => s.health);
        const trends = summaries.map(s => s.trend);
        const uniqueConf = new Set(confidences.map(c => Math.round(c * 10)));
        expect(uniqueConf.size).toBeGreaterThan(1);
        const uniqueHealth = new Set(healths.map(h => Math.round(h / 10)));
        expect(uniqueHealth.size).toBeGreaterThan(1);
        const uniqueTrends = new Set(trends);
        expect(uniqueTrends.size).toBeGreaterThan(1);
        const goodSummary = engine.getSummary('p_sim_0');
        const badSummary = engine.getSummary('p_sim_80');
        expect(goodSummary.confidence).toBeGreaterThan(badSummary.confidence);
        expect(goodSummary.health).toBeGreaterThan(badSummary.health);
        const lb = engine.generateLeaderboard();
        expect(lb.mostSuccessful.length).toBe(10);
        expect(lb.mostSuccessful[0].rank).toBe(1);
        expect(lb.mostSuccessful[9].rank).toBe(10);
        expect(lb.mostReliable.length).toBeGreaterThan(0);
        expect(lb.mostAccepted.length).toBeGreaterThan(0);
        expect(lb.fastestGrowing.length).toBeGreaterThan(0);
        expect(lb.mostFailed.length).toBeGreaterThan(0);
        expect(lb.mostRejected.length).toBeGreaterThan(0);
    });
    test('empty engine returns empty leaderboard', () => {
        const lb = engine.generateLeaderboard();
        expect(lb.mostSuccessful).toEqual([]);
        expect(lb.mostReliable).toEqual([]);
        expect(lb.generatedAt).toBeGreaterThan(0);
    });
});
//# sourceMappingURL=chapter3-verify.test.js.map