/**
 * Tests for cost pricing utilities
 */
import { describe, it, expect } from "vitest";
import { MODEL_PRICING, getModelProvider, getModelPricing, calculateCost, estimateCost, formatCost, formatTokens, estimateTokens, getSupportedModels, getModelsByProvider, getCheapestModel, } from "./pricing.js";
describe("Cost Pricing", () => {
    describe("MODEL_PRICING", () => {
        it("has pricing for claude-3.5-sonnet", () => {
            expect(MODEL_PRICING["claude-3.5-sonnet"]).toBeDefined();
            expect(MODEL_PRICING["claude-3.5-sonnet"].provider).toBe("anthropic");
        });
        it("has pricing for gpt-4-turbo", () => {
            expect(MODEL_PRICING["gpt-4-turbo"]).toBeDefined();
            expect(MODEL_PRICING["gpt-4-turbo"].provider).toBe("openai");
        });
        it("has pricing for gemini-1.5-pro", () => {
            expect(MODEL_PRICING["gemini-1.5-pro"]).toBeDefined();
            expect(MODEL_PRICING["gemini-1.5-pro"].provider).toBe("google");
        });
    });
    describe("getModelProvider", () => {
        it("returns anthropic for claude models", () => {
            expect(getModelProvider("claude-3.5-sonnet")).toBe("anthropic");
            expect(getModelProvider("claude-3-opus")).toBe("anthropic");
            expect(getModelProvider("claude-3-haiku")).toBe("anthropic");
        });
        it("returns openai for gpt models", () => {
            expect(getModelProvider("gpt-4-turbo")).toBe("openai");
            expect(getModelProvider("gpt-4o")).toBe("openai");
            expect(getModelProvider("gpt-4o-mini")).toBe("openai");
        });
        it("returns google for gemini models", () => {
            expect(getModelProvider("gemini-1.5-pro")).toBe("google");
            expect(getModelProvider("gemini-1.5-flash")).toBe("google");
        });
        it("returns anthropic as fallback for unrecognized models", () => {
            expect(getModelProvider("unknown-model")).toBe("anthropic");
        });
    });
    describe("getModelPricing", () => {
        it("returns pricing for known models", () => {
            const pricing = getModelPricing("claude-3.5-sonnet");
            expect(pricing).toBeDefined();
            expect(pricing.inputPer1M).toBeGreaterThan(0);
            expect(pricing.outputPer1M).toBeGreaterThan(0);
        });
        it("returns fallback pricing for unknown models", () => {
            const pricing = getModelPricing("unknown-model");
            expect(pricing).toBeDefined();
            // Falls back to claude-3.5-sonnet pricing
            expect(pricing.inputPer1M).toBe(3.0);
        });
    });
    describe("calculateCost", () => {
        it("calculates basic cost correctly", () => {
            const usage = {
                inputTokens: 1000,
                outputTokens: 500,
                totalTokens: 1500,
            };
            const cost = calculateCost("claude-3.5-sonnet", usage);
            // claude-3.5-sonnet: $3/1M input, $15/1M output
            // Input: 1000 tokens * $3/1M = $0.003
            // Output: 500 tokens * $15/1M = $0.0075
            expect(cost.inputCost).toBeCloseTo(0.003, 6);
            expect(cost.outputCost).toBeCloseTo(0.0075, 6);
            expect(cost.totalCost).toBeCloseTo(0.0105, 6);
        });
        it("applies cached token discount", () => {
            const usage = {
                inputTokens: 500,
                outputTokens: 500,
                cachedInputTokens: 500,
                totalTokens: 1500,
            };
            const cost = calculateCost("claude-3.5-sonnet", usage);
            // claude-3.5-sonnet: $3/1M input, $15/1M output, $0.30/1M cached
            // Input: 500 tokens * $3/1M = $0.0015
            // Cached: 500 tokens * $0.30/1M = $0.00015
            // Output: 500 tokens * $15/1M = $0.0075
            expect(cost.inputCost).toBeCloseTo(0.0015, 6);
            expect(cost.cachedInputCost).toBeCloseTo(0.00015, 6);
            expect(cost.outputCost).toBeCloseTo(0.0075, 6);
        });
        it("uses fallback pricing for unknown models", () => {
            const usage = {
                inputTokens: 1000,
                outputTokens: 500,
                totalTokens: 1500,
            };
            const cost = calculateCost("unknown-model", usage);
            // Uses claude-3.5-sonnet pricing as fallback
            expect(cost.totalCost).toBeGreaterThan(0);
        });
    });
    describe("estimateCost", () => {
        it("estimates cost from token counts", () => {
            const estimate = estimateCost("claude-3.5-sonnet", 1000, 500);
            // Same as calculateCost but without cached tokens
            expect(estimate).toBeCloseTo(0.0105, 6);
        });
        it("estimates with default output ratio when outputTokens not provided", () => {
            const estimate = estimateCost("claude-3.5-sonnet", 1000);
            // With 1000 input tokens, default output is 25% = 250 tokens
            // Input: 1000 * $3/1M = $0.003
            // Output: 250 * $15/1M = $0.00375
            expect(estimate).toBeCloseTo(0.00675, 6);
        });
        it("uses fallback pricing for unknown models", () => {
            const estimate = estimateCost("unknown-model", 1000, 500);
            expect(estimate).toBeGreaterThan(0);
        });
    });
    describe("formatCost", () => {
        it("formats small costs in cents", () => {
            // Values < $0.01 use cents notation
            expect(formatCost(0.001)).toBe("$0.100¢");
            expect(formatCost(0.0001)).toBe("$0.010¢");
        });
        it("formats larger costs with 4 decimals", () => {
            expect(formatCost(0.0105)).toBe("$0.0105");
            expect(formatCost(1.50)).toBe("$1.5000");
            expect(formatCost(10.00)).toBe("$10.0000");
        });
        it("handles zero", () => {
            expect(formatCost(0)).toBe("$0.000¢");
        });
    });
    describe("formatTokens", () => {
        it("formats small token counts without suffix", () => {
            expect(formatTokens(500)).toBe("500");
            expect(formatTokens(999)).toBe("999");
        });
        it("formats thousands with K suffix", () => {
            expect(formatTokens(1000)).toBe("1.0K");
            expect(formatTokens(5500)).toBe("5.5K");
            expect(formatTokens(10000)).toBe("10.0K");
        });
        it("formats millions with M suffix", () => {
            expect(formatTokens(1000000)).toBe("1.00M");
            expect(formatTokens(2500000)).toBe("2.50M");
        });
    });
    describe("estimateTokens", () => {
        it("estimates tokens from text", () => {
            // Roughly 4 characters per token
            const tokens = estimateTokens("Hello, world!"); // 13 chars
            expect(tokens).toBe(4); // ceil(13/4)
        });
        it("handles empty string", () => {
            expect(estimateTokens("")).toBe(0);
        });
        it("handles long text", () => {
            const longText = "a".repeat(1000);
            expect(estimateTokens(longText)).toBe(250);
        });
    });
    describe("getSupportedModels", () => {
        it("returns array of model IDs", () => {
            const models = getSupportedModels();
            expect(Array.isArray(models)).toBe(true);
            expect(models.length).toBeGreaterThan(0);
            expect(models).toContain("claude-3.5-sonnet");
            expect(models).toContain("gpt-4-turbo");
            expect(models).toContain("gemini-1.5-pro");
        });
    });
    describe("getModelsByProvider", () => {
        it("returns only anthropic models", () => {
            const models = getModelsByProvider("anthropic");
            expect(models.every((m) => m.startsWith("claude"))).toBe(true);
        });
        it("returns only openai models", () => {
            const models = getModelsByProvider("openai");
            expect(models.every((m) => m.startsWith("gpt") || m.startsWith("o"))).toBe(true);
        });
        it("returns only google models", () => {
            const models = getModelsByProvider("google");
            expect(models.every((m) => m.startsWith("gemini"))).toBe(true);
        });
    });
    describe("getCheapestModel", () => {
        it("returns cheapest model for provider", () => {
            const cheapest = getCheapestModel("anthropic");
            expect(cheapest).toBeDefined();
            // Haiku should be cheapest Claude model
            expect(cheapest).toBe("claude-3-haiku");
        });
        it("returns overall cheapest when no provider specified", () => {
            const cheapest = getCheapestModel();
            expect(cheapest).toBeDefined();
        });
    });
});
//# sourceMappingURL=pricing.test.js.map