import { FORMAT_TO_CONTENT_TYPE, flattenHeaders, getContext, getTestId, isAudioResponse, isErrorResponse, isTextResponse, resolveResponse, resolveStrictMode, serializeErrorResponse, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
import { matchFixtureDiagnostic } from "./router.js";
import { writeErrorResponse } from "./sse-writer.js";
import { applyChaos } from "./chaos.js";
import { proxyAndRecord } from "./recorder.js";

//#region src/elevenlabs-audio.ts
async function handleElevenLabsTTS(req, res, body, fixtures, defaults, journal, voiceId) {
	const path = req.url ?? `/v1/text-to-speech/${voiceId}`;
	const method = req.method ?? "POST";
	let parsed;
	try {
		parsed = JSON.parse(body);
	} catch (parseErr) {
		const detail = parseErr instanceof Error ? parseErr.message : "unknown";
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: `Malformed JSON: ${detail}`,
			type: "invalid_request_error",
			code: "invalid_json"
		} }));
		return;
	}
	const promptText = typeof parsed.text === "string" && parsed.text ? parsed.text : void 0;
	const syntheticReq = {
		model: parsed.model_id ?? "eleven_multilingual_v2",
		messages: [{
			role: "user",
			content: promptText ?? ""
		}],
		_endpointType: "elevenlabs-tts",
		_context: getContext(req)
	};
	if (!promptText) {
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 400,
				fixture: null
			}
		});
		writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: "Missing required parameter: 'text'",
			type: "invalid_request_error"
		} }));
		return;
	}
	const testId = getTestId(req);
	const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
	if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
	if (applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
		method,
		path,
		headers: flattenHeaders(req.headers),
		body: syntheticReq
	}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
	if (!fixture) {
		if (resolveStrictMode(defaults.strict, req.headers)) {
			const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);
			defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));
			journal.add({
				method,
				path,
				headers: flattenHeaders(req.headers),
				body: syntheticReq,
				response: {
					status: 503,
					fixture: null,
					...strictOverrideField(defaults.strict, req.headers)
				}
			});
			writeErrorResponse(res, 503, JSON.stringify({ error: {
				message: strictMessage,
				type: "invalid_request_error",
				code: "no_fixture_match"
			} }));
			return;
		}
		if (defaults.record) {
			const outcome = await proxyAndRecord(req, res, syntheticReq, "elevenlabs", req.url ?? `/v1/text-to-speech/${voiceId}`, fixtures, defaults, body);
			if (outcome === "handled_by_hook") return;
			if (outcome !== "not_configured") {
				journal.add({
					method,
					path,
					headers: flattenHeaders(req.headers),
					body: syntheticReq,
					response: {
						status: res.statusCode ?? 200,
						fixture: null,
						source: "proxy"
					}
				});
				return;
			}
		}
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 404,
				fixture: null,
				...strictOverrideField(defaults.strict, req.headers)
			}
		});
		writeErrorResponse(res, 404, JSON.stringify({ error: {
			message: "No fixture matched",
			type: "invalid_request_error",
			code: "no_fixture_match"
		} }));
		return;
	}
	const response = await resolveResponse(fixture, syntheticReq);
	if (isErrorResponse(response)) {
		const status = response.status ?? 500;
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status,
				fixture
			}
		});
		writeErrorResponse(res, status, serializeErrorResponse(response), { retryAfter: response.retryAfter });
		return;
	}
	if (!isAudioResponse(response)) {
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 500,
				fixture
			}
		});
		writeErrorResponse(res, 500, JSON.stringify({ error: {
			message: "Fixture response is not an audio type",
			type: "server_error"
		} }));
		return;
	}
	let audioBytes;
	let contentType;
	if (typeof response.audio === "string") {
		audioBytes = Buffer.from(response.audio, "base64");
		contentType = FORMAT_TO_CONTENT_TYPE[response.format ?? "mp3"] ?? "audio/mpeg";
	} else {
		audioBytes = Buffer.from(response.audio.b64Json, "base64");
		contentType = response.audio.contentType ?? "audio/mpeg";
	}
	journal.add({
		method,
		path,
		headers: flattenHeaders(req.headers),
		body: syntheticReq,
		response: {
			status: 200,
			fixture
		}
	});
	res.writeHead(200, { "Content-Type": contentType });
	res.end(audioBytes);
}
async function handleElevenLabsAudio(req, res, body, fixtures, defaults, journal, subType) {
	const path = req.url ?? "/v1/sound-generation";
	const method = req.method ?? "POST";
	let parsed;
	try {
		parsed = JSON.parse(body);
	} catch (parseErr) {
		const detail = parseErr instanceof Error ? parseErr.message : "unknown";
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: null,
			response: {
				status: 400,
				fixture: null
			}
		});
		writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: `Malformed JSON: ${detail}`,
			type: "invalid_request_error",
			code: "invalid_json"
		} }));
		return;
	}
	let promptText;
	if (subType === "sound-generation") {
		if (typeof parsed.text === "string" && parsed.text) promptText = parsed.text;
	} else if (typeof parsed.prompt === "string" && parsed.prompt) promptText = parsed.prompt;
	else if (parsed.composition_plan != null) promptText = typeof parsed.composition_plan === "string" ? parsed.composition_plan : JSON.stringify(parsed.composition_plan);
	const syntheticReq = {
		model: parsed.model_id ?? (subType === "sound-generation" ? "eleven_text_to_sound_v2" : "music_v1"),
		messages: [{
			role: "user",
			content: promptText ?? ""
		}],
		_endpointType: "audio-gen",
		_context: getContext(req)
	};
	if (!promptText) {
		const field = subType === "sound-generation" ? "text" : "prompt";
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 400,
				fixture: null
			}
		});
		writeErrorResponse(res, 400, JSON.stringify({ error: {
			message: `Missing required parameter: '${field}'`,
			type: "invalid_request_error"
		} }));
		return;
	}
	const testId = getTestId(req);
	const { fixture, skippedBySequenceOrTurn } = matchFixtureDiagnostic(fixtures, syntheticReq, journal.getFixtureMatchCountsForTest(testId), defaults.requestTransform);
	if (fixture) journal.incrementFixtureMatchCount(fixture, fixtures, testId);
	if (applyChaos(res, fixture, defaults.chaos, req.headers, journal, {
		method,
		path,
		headers: flattenHeaders(req.headers),
		body: syntheticReq
	}, fixture ? "fixture" : "proxy", defaults.registry, defaults.logger)) return;
	if (!fixture) {
		if (resolveStrictMode(defaults.strict, req.headers)) {
			const strictMessage = strictNoMatchMessage(skippedBySequenceOrTurn);
			defaults.logger.error(strictNoMatchLogLine(method, path, skippedBySequenceOrTurn));
			journal.add({
				method,
				path,
				headers: flattenHeaders(req.headers),
				body: syntheticReq,
				response: {
					status: 503,
					fixture: null,
					...strictOverrideField(defaults.strict, req.headers)
				}
			});
			writeErrorResponse(res, 503, JSON.stringify({ error: {
				message: strictMessage,
				type: "invalid_request_error",
				code: "no_fixture_match"
			} }));
			return;
		}
		if (defaults.record) {
			const outcome = await proxyAndRecord(req, res, syntheticReq, "elevenlabs", req.url ?? "/v1/sound-generation", fixtures, defaults, body);
			if (outcome === "handled_by_hook") return;
			if (outcome !== "not_configured") {
				journal.add({
					method,
					path,
					headers: flattenHeaders(req.headers),
					body: syntheticReq,
					response: {
						status: res.statusCode ?? 200,
						fixture: null,
						source: "proxy"
					}
				});
				return;
			}
		}
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 404,
				fixture: null,
				...strictOverrideField(defaults.strict, req.headers)
			}
		});
		writeErrorResponse(res, 404, JSON.stringify({ error: {
			message: "No fixture matched",
			type: "invalid_request_error",
			code: "no_fixture_match"
		} }));
		return;
	}
	const response = await resolveResponse(fixture, syntheticReq);
	if (isErrorResponse(response)) {
		const status = response.status ?? 500;
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status,
				fixture
			}
		});
		writeErrorResponse(res, status, serializeErrorResponse(response), { retryAfter: response.retryAfter });
		return;
	}
	if (subType === "plan") {
		if (!isTextResponse(response)) {
			journal.add({
				method,
				path,
				headers: flattenHeaders(req.headers),
				body: syntheticReq,
				response: {
					status: 500,
					fixture
				}
			});
			writeErrorResponse(res, 500, JSON.stringify({ error: {
				message: "Fixture response is not a text type for plan endpoint",
				type: "server_error"
			} }));
			return;
		}
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 200,
				fixture
			}
		});
		res.writeHead(200, { "Content-Type": "application/json" });
		res.end(response.content);
		return;
	}
	if (!isAudioResponse(response)) {
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 500,
				fixture
			}
		});
		writeErrorResponse(res, 500, JSON.stringify({ error: {
			message: "Fixture response is not an audio type",
			type: "server_error"
		} }));
		return;
	}
	let audioBytes;
	let contentType;
	if (typeof response.audio === "string") {
		audioBytes = Buffer.from(response.audio, "base64");
		contentType = FORMAT_TO_CONTENT_TYPE[response.format ?? "mp3"] ?? "audio/mpeg";
	} else {
		audioBytes = Buffer.from(response.audio.b64Json, "base64");
		contentType = response.audio.contentType ?? "audio/mpeg";
	}
	if (subType === "music" || subType === "stream") res.setHeader("song-id", "mock-song-" + Date.now());
	if (subType === "stream") {
		journal.add({
			method,
			path,
			headers: flattenHeaders(req.headers),
			body: syntheticReq,
			response: {
				status: 200,
				fixture
			}
		});
		res.writeHead(200, {
			"Content-Type": contentType,
			"Transfer-Encoding": "chunked"
		});
		res.end(audioBytes);
		return;
	}
	journal.add({
		method,
		path,
		headers: flattenHeaders(req.headers),
		body: syntheticReq,
		response: {
			status: 200,
			fixture
		}
	});
	res.writeHead(200, { "Content-Type": contentType });
	res.end(audioBytes);
}

//#endregion
export { handleElevenLabsAudio, handleElevenLabsTTS };
//# sourceMappingURL=elevenlabs-audio.js.map