// npx vitest run api/providers/fetchers/__tests__/openrouter.spec.ts

import * as path from "path"

import { back as nockBack } from "nock"

import { getOpenRouterModelEndpoints, getOpenRouterModels, parseOpenRouterModel } from "../openrouter"

nockBack.fixtures = path.join(__dirname, "fixtures")
nockBack.setMode("lockdown")

describe("OpenRouter API", () => {
	describe("getOpenRouterModels", () => {
		it("fetches models and validates schema", async () => {
			const { nockDone } = await nockBack("openrouter-models.json")

			const models = await getOpenRouterModels()

			expect(models["anthropic/claude-3.7-sonnet"]).toEqual({
				maxTokens: 8192,
				contextWindow: 200000,
				supportsImages: true,
				supportsPromptCache: true,
				inputPrice: 3,
				outputPrice: 15,
				cacheWritesPrice: 3.75,
				cacheReadsPrice: 0.3,
				description: expect.any(String),
				supportsReasoningBudget: false,
				supportsReasoningEffort: false,
				supportedParameters: ["max_tokens", "temperature", "reasoning", "include_reasoning"],
			})

			expect(models["anthropic/claude-3.7-sonnet:thinking"]).toEqual({
				maxTokens: 128000,
				contextWindow: 200000,
				supportsImages: true,
				supportsPromptCache: true,
				inputPrice: 3,
				outputPrice: 15,
				cacheWritesPrice: 3.75,
				cacheReadsPrice: 0.3,
				description: expect.any(String),
				supportsReasoningBudget: true,
				requiredReasoningBudget: true,
				supportsReasoningEffort: true,
				supportedParameters: ["max_tokens", "temperature", "reasoning", "include_reasoning"],
			})

			expect(models["google/gemini-2.5-flash-preview-05-20"].maxTokens).toEqual(65535)

			const anthropicModels = Object.entries(models)
				.filter(([id, _]) => id.startsWith("anthropic/claude-3"))
				.map(([id, model]) => ({ id, maxTokens: model.maxTokens }))
				.sort(({ id: a }, { id: b }) => a.localeCompare(b))

			expect(anthropicModels).toEqual([
				{ id: "anthropic/claude-3-haiku", maxTokens: 4096 },
				{ id: "anthropic/claude-3-haiku:beta", maxTokens: 4096 },
				{ id: "anthropic/claude-3-opus", maxTokens: 4096 },
				{ id: "anthropic/claude-3-opus:beta", maxTokens: 4096 },
				{ id: "anthropic/claude-3-sonnet", maxTokens: 4096 },
				{ id: "anthropic/claude-3-sonnet:beta", maxTokens: 4096 },
				{ id: "anthropic/claude-3.5-haiku", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-haiku-20241022", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-haiku-20241022:beta", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-haiku:beta", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-sonnet", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-sonnet-20240620", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-sonnet-20240620:beta", maxTokens: 8192 },
				{ id: "anthropic/claude-3.5-sonnet:beta", maxTokens: 8192 },
				{ id: "anthropic/claude-3.7-sonnet", maxTokens: 8192 },
				{ id: "anthropic/claude-3.7-sonnet:beta", maxTokens: 128000 },
				{ id: "anthropic/claude-3.7-sonnet:thinking", maxTokens: 128000 },
			])

			nockDone()
		})
	})

	describe("getOpenRouterModelEndpoints", () => {
		it("fetches model endpoints and validates schema", async () => {
			const { nockDone } = await nockBack("openrouter-model-endpoints.json")
			const endpoints = await getOpenRouterModelEndpoints("google/gemini-2.5-pro-preview")

			expect(endpoints).toEqual({
				"google-vertex": {
					maxTokens: 65535,
					contextWindow: 1048576,
					supportsImages: true,
					supportsPromptCache: true,
					supportsReasoningBudget: true,
					inputPrice: 1.25,
					outputPrice: 10,
					cacheWritesPrice: 1.625,
					cacheReadsPrice: 0.31,
					description: undefined,
					supportsReasoningEffort: undefined,
					supportedParameters: undefined,
				},
				"google-ai-studio": {
					maxTokens: 65536,
					contextWindow: 1048576,
					supportsImages: true,
					supportsPromptCache: true,
					supportsReasoningBudget: true,
					inputPrice: 1.25,
					outputPrice: 10,
					cacheWritesPrice: 1.625,
					cacheReadsPrice: 0.31,
					description: undefined,
					supportsReasoningEffort: undefined,
					supportedParameters: undefined,
				},
			})

			nockDone()
		})
	})

	describe("parseOpenRouterModel", () => {
		it("sets horizon-alpha model to 32k max tokens", () => {
			const mockModel = {
				name: "Horizon Alpha",
				description: "Test model",
				context_length: 128000,
				max_completion_tokens: 128000,
				pricing: {
					prompt: "0.000003",
					completion: "0.000015",
				},
			}

			const result = parseOpenRouterModel({
				id: "openrouter/horizon-alpha",
				model: mockModel,
				inputModality: ["text"],
				outputModality: ["text"],
				maxTokens: 128000,
			})

			expect(result.maxTokens).toBe(32768)
			expect(result.contextWindow).toBe(128000)
		})

		it("sets horizon-beta model to 32k max tokens", () => {
			const mockModel = {
				name: "Horizon Beta",
				description: "Test model",
				context_length: 128000,
				max_completion_tokens: 128000,
				pricing: {
					prompt: "0.000003",
					completion: "0.000015",
				},
			}

			const result = parseOpenRouterModel({
				id: "openrouter/horizon-beta",
				model: mockModel,
				inputModality: ["text"],
				outputModality: ["text"],
				maxTokens: 128000,
			})

			expect(result.maxTokens).toBe(32768)
			expect(result.contextWindow).toBe(128000)
		})

		it("does not override max tokens for other models", () => {
			const mockModel = {
				name: "Other Model",
				description: "Test model",
				context_length: 128000,
				max_completion_tokens: 64000,
				pricing: {
					prompt: "0.000003",
					completion: "0.000015",
				},
			}

			const result = parseOpenRouterModel({
				id: "openrouter/other-model",
				model: mockModel,
				inputModality: ["text"],
				outputModality: ["text"],
				maxTokens: 64000,
			})

			expect(result.maxTokens).toBe(64000)
			expect(result.contextWindow).toBe(128000)
		})

		it("filters out image generation models", () => {
			const mockImageModel = {
				name: "Image Model",
				description: "Test image generation model",
				context_length: 128000,
				max_completion_tokens: 64000,
				pricing: {
					prompt: "0.000003",
					completion: "0.000015",
				},
			}

			const mockTextModel = {
				name: "Text Model",
				description: "Test text generation model",
				context_length: 128000,
				max_completion_tokens: 64000,
				pricing: {
					prompt: "0.000003",
					completion: "0.000015",
				},
			}

			// Model with image output should be filtered out - we only test parseOpenRouterModel
			// since the filtering happens in getOpenRouterModels/getOpenRouterModelEndpoints
			const textResult = parseOpenRouterModel({
				id: "test/text-model",
				model: mockTextModel,
				inputModality: ["text"],
				outputModality: ["text"],
				maxTokens: 64000,
			})

			const imageResult = parseOpenRouterModel({
				id: "test/image-model",
				model: mockImageModel,
				inputModality: ["text"],
				outputModality: ["image"],
				maxTokens: 64000,
			})

			// Both should parse successfully (filtering happens at a higher level)
			expect(textResult.maxTokens).toBe(64000)
			expect(imageResult.maxTokens).toBe(64000)
		})
	})
})
