/**
 * Tests for multi-model runner
 */
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { MultiModelRunner, DEFAULT_MODELS, getRunner, resetRunner, formatProvider, } from "./runner.js";
describe("MultiModelRunner", () => {
    let runner;
    // Helper to create mock findings
    function createFinding(overrides = {}) {
        return {
            id: `finding-${Math.random().toString(36).slice(2, 8)}`,
            description: overrides.description || "A test finding description",
            severity: "medium",
            category: "security",
            evidence: "Test evidence",
            confidence: 80,
            verifications: [],
            created_at: new Date().toISOString(),
            ...overrides,
        };
    }
    beforeEach(() => {
        runner = new MultiModelRunner();
    });
    afterEach(() => {
        resetRunner();
    });
    describe("constructor", () => {
        it("initializes with default models", () => {
            const enabled = runner.getEnabledModels();
            expect(enabled.length).toBe(DEFAULT_MODELS.length);
        });
        it("accepts custom configuration", () => {
            const customRunner = new MultiModelRunner({
                models: [
                    { id: "claude-3.5-sonnet", provider: "anthropic", weight: 2.0, enabled: true },
                ],
            });
            const models = customRunner.getEnabledModels();
            expect(models.length).toBe(1);
            expect(models[0].weight).toBe(2.0);
        });
    });
    describe("getEnabledModels", () => {
        it("returns only enabled models", () => {
            runner.setModelEnabled("gpt-4-turbo", false);
            const enabled = runner.getEnabledModels();
            expect(enabled.some((m) => m.id === "claude-3.5-sonnet")).toBe(true);
            expect(enabled.some((m) => m.id === "gpt-4-turbo")).toBe(false);
        });
    });
    describe("setModelEnabled", () => {
        it("enables/disables models", () => {
            runner.setModelEnabled("gemini-1.5-pro", false);
            expect(runner.getEnabledModels().some((m) => m.id === "gemini-1.5-pro")).toBe(false);
            runner.setModelEnabled("gemini-1.5-pro", true);
            expect(runner.getEnabledModels().some((m) => m.id === "gemini-1.5-pro")).toBe(true);
        });
    });
    describe("addModel", () => {
        it("adds new model configuration", () => {
            runner.addModel({
                id: "claude-3-opus",
                provider: "anthropic",
                weight: 1.5,
                enabled: true,
            });
            const config = runner.getModelConfig("claude-3-opus");
            expect(config).toBeDefined();
            expect(config.weight).toBe(1.5);
        });
        it("updates existing model configuration", () => {
            runner.addModel({
                id: "claude-3.5-sonnet",
                provider: "anthropic",
                weight: 3.0,
                enabled: true,
            });
            const config = runner.getModelConfig("claude-3.5-sonnet");
            expect(config.weight).toBe(3.0);
        });
    });
    describe("recordResult", () => {
        it("records successful model run", () => {
            const finding = createFinding();
            const result = runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            expect(result.model).toBe("claude-3.5-sonnet");
            expect(result.provider).toBe("anthropic");
            expect(result.findings.length).toBe(1);
            expect(result.success).toBe(true);
            expect(result.cost).toBeGreaterThan(0);
        });
        it("stores results by certification and agent", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            const results = runner.getResults("cert-123", "security");
            expect(results.length).toBe(1);
            const otherResults = runner.getResults("cert-456", "security");
            expect(otherResults.length).toBe(0);
        });
    });
    describe("recordFailure", () => {
        it("records failed model run", () => {
            const result = runner.recordFailure("cert-123", "security", "gpt-4-turbo", "API timeout", 5000);
            expect(result.model).toBe("gpt-4-turbo");
            expect(result.success).toBe(false);
            expect(result.error).toBe("API timeout");
            expect(result.findings.length).toBe(0);
        });
    });
    describe("hasEnoughResults", () => {
        it("returns false when no results", () => {
            expect(runner.hasEnoughResults("cert-123", "security")).toBe(false);
        });
        it("returns false when fewer than minModels", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            expect(runner.hasEnoughResults("cert-123", "security")).toBe(false);
        });
        it("returns true when enough successful results", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "security", "gpt-4-turbo", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            expect(runner.hasEnoughResults("cert-123", "security")).toBe(true);
        });
        it("does not count failed results", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordFailure("cert-123", "security", "gpt-4-turbo", "Error", 1000);
            expect(runner.hasEnoughResults("cert-123", "security")).toBe(false);
        });
    });
    describe("calculateConsensus", () => {
        it("returns null when no results", () => {
            expect(runner.calculateConsensus("cert-123", "security")).toBeNull();
        });
        it("calculates consensus when results available", () => {
            const finding = createFinding({
                file: "src/auth.ts",
                line: 42,
                description: "SQL Injection",
            });
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [{ ...finding, id: "c1" }], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "security", "gpt-4-turbo", [{ ...finding, id: "g1" }], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            const consensus = runner.calculateConsensus("cert-123", "security");
            expect(consensus).not.toBeNull();
            expect(consensus.models.length).toBe(2);
            expect(consensus.metrics.agreementRate).toBe(100);
        });
    });
    describe("generateSummary", () => {
        it("returns null when no results", () => {
            expect(runner.generateSummary("cert-123", "security")).toBeNull();
        });
        it("generates summary with cost and token info", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "security", "gpt-4-turbo", [finding], { duration: 1000, inputTokens: 2000, outputTokens: 1000 });
            const summary = runner.generateSummary("cert-123", "security");
            expect(summary).not.toBeNull();
            expect(summary.totalModels).toBe(2);
            expect(summary.successfulModels).toBe(2);
            expect(summary.totalCost).toBeGreaterThan(0);
            expect(summary.totalTokens).toBe(4500);
        });
    });
    describe("generateReport", () => {
        it("generates markdown report", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "security", "gpt-4-turbo", [finding], { duration: 1000, inputTokens: 2000, outputTokens: 1000 });
            const report = runner.generateReport("cert-123", "security");
            expect(report).toContain("# Multi-Model Consensus Report");
            expect(report).toContain("## Cost Summary");
            expect(report).toContain("## Individual Model Results");
            expect(report).toContain("claude-3.5-sonnet");
            expect(report).toContain("gpt-4-turbo");
        });
    });
    describe("clearResults", () => {
        it("clears results for specific agent", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "reliability", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.clearResults("cert-123", "security");
            expect(runner.getResults("cert-123", "security").length).toBe(0);
            expect(runner.getResults("cert-123", "reliability").length).toBe(1);
        });
        it("clears all results for certification when no agent specified", () => {
            const finding = createFinding();
            runner.recordResult("cert-123", "security", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.recordResult("cert-123", "reliability", "claude-3.5-sonnet", [finding], { duration: 1000, inputTokens: 1000, outputTokens: 500 });
            runner.clearResults("cert-123");
            expect(runner.getResults("cert-123", "security").length).toBe(0);
            expect(runner.getResults("cert-123", "reliability").length).toBe(0);
        });
    });
});
describe("Global Runner", () => {
    afterEach(() => {
        resetRunner();
    });
    describe("getRunner", () => {
        it("returns same instance on subsequent calls", () => {
            const runner1 = getRunner();
            const runner2 = getRunner();
            expect(runner1).toBe(runner2);
        });
        it("creates new instance after reset", () => {
            const runner1 = getRunner();
            resetRunner();
            const runner2 = getRunner();
            expect(runner1).not.toBe(runner2);
        });
    });
});
describe("formatProvider", () => {
    it("formats provider names", () => {
        expect(formatProvider("anthropic")).toBe("Anthropic");
        expect(formatProvider("openai")).toBe("OpenAI");
        expect(formatProvider("google")).toBe("Google");
    });
});
//# sourceMappingURL=runner.test.js.map