import assert from "node:assert/strict";
import { describe, it } from "vitest";
import { resolveWireModelId } from "../model-identity.js";
import type { Context, Model, OpenAICompletionsCompat } from "../types.js";
import {
	convertMessages,
	streamOpenAICompletions,
} from "./openai-completions.js";

const compat = {
	supportsDeveloperRole: false,
	requiresAssistantAfterToolResult: false,
	requiresThinkingAsText: false,
} as Required<OpenAICompletionsCompat>;

function model(provider: string, id: string): Model<"openai-completions"> {
	return {
		id,
		name: id,
		api: "openai-completions",
		provider,
		baseUrl:
			provider === "openrouter"
				? "https://openrouter.ai/api/v1"
				: "https://api.openai.com/v1",
		reasoning: false,
		input: ["text"],
		cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
		contextWindow: 128_000,
		maxTokens: 4096,
	};
}

function contextWithCacheControl(): Context {
	return {
		messages: [
			{
				role: "user",
				content: [
					{
						type: "text",
						text: "stable prefix",
						cache_control: { type: "ephemeral" },
					} as any,
					{ type: "text", text: "dynamic suffix" },
				],
				timestamp: Date.now(),
			},
		],
	};
}

describe("convertMessages cache_control", () => {
	it("preserves_cache_control_when_openrouter_anthropic_model", () => {
		const messages = convertMessages(
			model("openrouter", "anthropic/claude-sonnet-4.5"),
			contextWithCacheControl(),
			compat,
		);

		const content = messages[0].content;
		assert.ok(Array.isArray(content));
		assert.deepEqual((content[0] as any).cache_control, {
			type: "ephemeral",
		});
	});

	it("strips_cache_control_when_openai_compatible_model_does_not_support_it", () => {
		const messages = convertMessages(
			model("openai", "gpt-5.3-chat-latest"),
			contextWithCacheControl(),
			compat,
		);

		const content = messages[0].content;
		assert.ok(Array.isArray(content));
		assert.equal((content[0] as any).cache_control, undefined);
	});
});

describe("wire model identity", () => {
	it("resolveWireModelId_when_wireModelId_missing_returns_canonical_id", () => {
		const selected = model("custom", "canonical-model");

		assert.equal(resolveWireModelId(selected), "canonical-model");
	});

	it("openai_payload_when_wireModelId_set_sends_wire_id_and_preserves_canonical_history", async () => {
		const selected = {
			...model("custom", "canonical-model"),
			wireModelId: "provider-deployment",
		};
		let payloadModel: unknown;
		let observedModelId: string | undefined;

		const stream = streamOpenAICompletions(
			selected,
			{
				messages: [{ role: "user", content: "hello", timestamp: Date.now() }],
			},
			{
				apiKey: "test-key",
				onPayload: (payload, observedModel) => {
					payloadModel = (payload as { model?: unknown }).model;
					observedModelId = observedModel.id;
					throw new Error("stop before network");
				},
			},
		);

		const result = await stream.result();

		assert.equal(payloadModel, "provider-deployment");
		assert.equal(observedModelId, "canonical-model");
		assert.equal(result.model, "canonical-model");
		assert.equal(result.stopReason, "error");
		assert.match(result.errorMessage ?? "", /stop before network/);
	});
});
