import { describe, expect, it } from "bun:test";
import { getBundledModel } from "@oh-my-pi/pi-ai/models";
import { streamOpenAICompletions } from "@oh-my-pi/pi-ai/providers/openai-completions";
import { detectOpenAICompat, resolveOpenAICompat } from "@oh-my-pi/pi-ai/providers/openai-completions-compat";
import type { Context, Model, Tool } from "@oh-my-pi/pi-ai/types";
import * as z from "zod/v4";

const echoTool: Tool = {
	name: "echo",
	description: "Echo input",
	parameters: z.object({ text: z.string() }),
};

const contextWithTools: Context = {
	messages: [{ role: "user", content: "call echo", timestamp: Date.now() }],
	tools: [echoTool],
};

function abortedSignal(): AbortSignal {
	const controller = new AbortController();
	controller.abort();
	return controller.signal;
}

async function capturePayload(model: Model<"openai-completions">): Promise<Record<string, unknown>> {
	const { promise, resolve } = Promise.withResolvers<unknown>();
	streamOpenAICompletions(model, contextWithTools, {
		apiKey: "test-key",
		signal: abortedSignal(),
		reasoning: "minimal",
		toolChoice: "auto",
		maxTokens: 123,
		onPayload: payload => resolve(payload),
	});
	return (await promise) as Record<string, unknown>;
}

function customDeepseekFlash(): Model<"openai-completions"> {
	return {
		...getBundledModel("openai", "gpt-4o-mini"),
		api: "openai-completions",
		id: "deepseek-v4-flash",
		name: "DeepSeek V4 Flash",
		provider: "ds",
		baseUrl: "https://api.deepseek.com/v1",
		reasoning: true,
		compat: {
			supportsReasoningEffort: true,
			reasoningEffortMap: { xhigh: "max" },
		},
	};
}

describe("issue #1207 — DeepSeek V4 keeps reasoning with tools", () => {
	it("detects the documented direct DeepSeek V4 compat shape", () => {
		const model = getBundledModel("deepseek", "deepseek-v4-flash") as Model<"openai-completions">;
		const compat = detectOpenAICompat(model);

		expect(compat.supportsToolChoice).toBe(false);
		expect(compat.maxTokensField).toBe("max_tokens");
		expect(compat.extraBody).toEqual({ thinking: { type: "enabled" } });
		expect(compat.reasoningEffortMap).toMatchObject({
			minimal: "high",
			low: "high",
			medium: "high",
			high: "high",
			xhigh: "max",
		});
	});

	it("merges partial user reasoning maps with DeepSeek defaults", () => {
		const compat = resolveOpenAICompat(customDeepseekFlash());

		expect(compat.supportsToolChoice).toBe(false);
		expect(compat.reasoningEffortMap).toMatchObject({
			minimal: "high",
			low: "high",
			medium: "high",
			xhigh: "max",
		});
	});

	it("omits tool_choice but preserves documented reasoning when tools are present", async () => {
		const body = await capturePayload(customDeepseekFlash());

		expect(body.tools).toBeDefined();
		expect(body.tool_choice).toBeUndefined();
		expect(body.reasoning_effort).toBe("high");
		expect(body.thinking).toEqual({ type: "enabled" });
		expect(body.max_tokens).toBe(123);
		expect(body.max_completion_tokens).toBeUndefined();
	});

	it("preserves OpenRouter reasoning when tool_choice auto is present", async () => {
		const model = getBundledModel("openrouter", "deepseek/deepseek-v4-flash") as Model<"openai-completions">;
		const compat = detectOpenAICompat(model);
		const body = await capturePayload(model);

		expect(compat.disableReasoningOnToolChoice).toBe(false);
		expect(body.tools).toBeDefined();
		expect(body.tool_choice).toBe("auto");
		expect(body.reasoning).toEqual({ effort: "high" });
		expect(body.reasoning_effort).toBeUndefined();
	});
});