import assert from "node:assert/strict";
import { afterEach, describe, test, vi } from "vitest";

const voiceRoute = await import("../../../web/app/api/voice/route.ts");
const voicePromptRoute = await import(
	"../../../web/app/api/voice/prompt/route.ts"
);

const ENV_KEYS = [
	"ELEVENLABS_API_KEY",
	"ELEVENLABS_VOICE_ID",
	"ELEVENLABS_MODEL_ID",
	"TWILIO_IVR_AI_NUMBER",
	"TWILIO_IVR_AI_NUMBERS",
	"TWILIO_IVR_ONCALL_NUMBER",
	"TWILIO_IVR_ONCALL_NUMBERS",
	"TWILIO_ONCALL_NUMBER",
	"ONCALL_NUMBER",
] as const;

const originalEnv = Object.fromEntries(
	ENV_KEYS.map((key) => [key, process.env[key]]),
) as Partial<Record<(typeof ENV_KEYS)[number], string | undefined>>;

function setEnv(
	values: Partial<Record<(typeof ENV_KEYS)[number], string | undefined>>,
): void {
	for (const key of ENV_KEYS) {
		const value = values[key];
		if (value === undefined) {
			delete process.env[key];
		} else {
			process.env[key] = value;
		}
	}
}

afterEach(() => {
	setEnv(originalEnv);
	vi.unstubAllGlobals();
});

describe("voice IVR", () => {
	test("voice_GET_when_oncall_number_configured_renders_menu", async () => {
		setEnv({
			TWILIO_IVR_ONCALL_NUMBER: "+16175551212",
		});

		const response = await voiceRoute.GET(
			new Request("http://localhost/api/voice"),
		);
		const xml = await response.text();

		assert.equal(
			response.headers.get("content-type"),
			"text/xml; charset=utf-8",
		);
		assert.match(xml, /<Gather input="dtmf" numDigits="1" timeout="6"/);
		assert.match(xml, /Welcome to Singularity Forge\./);
		assert.match(xml, /Press 1 to reach the on-call line\./);
		assert.match(xml, /Press 9 to repeat this menu\./);
		assert.doesNotMatch(xml, /Press 2 for the AI assistant\./);
	});

	test("voice_POST_when_digit_one_dials_oncall_number", async () => {
		setEnv({
			TWILIO_IVR_ONCALL_NUMBERS: "+16175551212,+16175551213",
		});

		const response = await voiceRoute.POST(
			new Request("http://localhost/api/voice", {
				method: "POST",
				headers: {
					"Content-Type": "application/x-www-form-urlencoded",
				},
				body: "Digits=1",
			}),
		);
		const xml = await response.text();

		assert.match(xml, /<Dial answerOnBridge="true" timeout="20">/);
		assert.match(xml, /<Number>\+16175551212<\/Number>/);
		assert.match(xml, /<Number>\+16175551213<\/Number>/);
	});

	test("voice_GET_when_elevenlabs_configured_uses_prompt_audio", async () => {
		setEnv({
			ELEVENLABS_API_KEY: "test-api-key",
			ELEVENLABS_VOICE_ID: "voice-123",
			ELEVENLABS_MODEL_ID: "eleven_flash_v2_5",
			TWILIO_IVR_ONCALL_NUMBER: "+16175551212",
		});

		const response = await voiceRoute.GET(
			new Request("https://example.com/api/voice"),
		);
		const xml = await response.text();

		assert.match(xml, /<Play>https:\/\/example\.com\/api\/voice\/prompt\?/);
		assert.match(xml, /text=Welcome\+to\+Singularity\+Forge\./);
	});

	test("voice_prompt_GET_when_configured_returns_audio", async () => {
		setEnv({
			ELEVENLABS_API_KEY: "test-api-key",
			ELEVENLABS_VOICE_ID: "voice-123",
			ELEVENLABS_MODEL_ID: "eleven_flash_v2_5",
		});

		const fetchCalls: Array<[string, RequestInit | undefined]> = [];
		vi.stubGlobal(
			"fetch",
			vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
				fetchCalls.push([String(input), init]);
				return new Response(new Uint8Array([1, 2, 3]), {
					headers: {
						"content-type": "audio/mpeg",
					},
				});
			}),
		);

		const response = await voicePromptRoute.GET(
			new Request(
				"https://example.com/api/voice/prompt?text=Welcome%20to%20Singularity%20Forge.",
			),
		);
		const body = new Uint8Array(await response.arrayBuffer());

		assert.equal(response.status, 200);
		assert.equal(response.headers.get("content-type"), "audio/mpeg");
		assert.deepEqual(Array.from(body), [1, 2, 3]);
		assert.equal(fetchCalls.length, 1);
		assert.match(
			fetchCalls[0]![0],
			/https:\/\/api\.elevenlabs\.io\/v1\/text-to-speech\/voice-123\?output_format=mp3_44100_128/,
		);
		assert.equal(
			(fetchCalls[0]![1]?.headers as Record<string, string>)["xi-api-key"],
			"test-api-key",
		);
	});
});
