import { createLogger } from "../../../utils/logger/index.js";
import { init_logger } from "../../../utils/logger.js";
import { pickTimeoutMsOrFallback } from "../../../media-shared/http/deadline.js";
import { privateNetworkPolicyToSsrfGuardOptions } from "../../../media-shared/http/private-network.js";
import { resolveProviderHttpRequestConfig } from "../../../media-shared/http/resolve-provider-http-request-config.js";
import { postJsonRequest, postMultipartRequest } from "../../../media-shared/http/provider-http.js";
import "../../../media-shared/http/index.js";
import { imageAssetFromBase64, imageFileExtensionForMimeType } from "./image-assets.js";
//#region src/agent/image/generation/openai-compatible-image-provider.ts
init_logger();
const log = createLogger("ImageGen:OpenAICompat");
const DEFAULT_OUTPUT_MIME = "image/png";
const DEFAULT_TIMEOUT_MS = 12e4;
function createOpenAiCompatibleImageProvider(options) {
	const defaultMaxCount = options.capabilities.generate?.maxCount ?? 4;
	const defaultCount = options.defaultCount ?? 1;
	const defaultSize = options.defaultSize ?? "1024x1024";
	return {
		id: options.id,
		...options.aliases ? { aliases: options.aliases } : {},
		...options.label ? { label: options.label } : {},
		defaultModel: options.defaultModel,
		models: options.models,
		capabilities: options.capabilities,
		isConfigured: options.isConfigured,
		...options.ui ? { ui: options.ui } : {},
		async generateImage(req) {
			const apiKey = options.resolveApiKey(req) ?? null;
			const endpoint = options.resolveEndpoint(req);
			const httpDefaults = resolveProviderHttpRequestConfig({
				providerId: options.id,
				cfg: req.cfg,
				fallbackTimeoutMs: options.defaultTimeoutMs ?? DEFAULT_TIMEOUT_MS
			});
			const headers = {
				...httpDefaults.headers,
				...endpoint.headers ?? {}
			};
			applyAuthorizationHeader({
				headers,
				endpoint,
				apiKey
			});
			const isEdit = (req.inputImages?.length ?? 0) > 0;
			const count = clampCount(req.count, defaultCount, defaultMaxCount);
			const size = req.size?.trim() || defaultSize;
			const url = isEdit ? joinPath(endpoint.baseUrl, endpoint.editsPath ?? "/images/edits") : joinPath(endpoint.baseUrl, endpoint.generationsPath ?? "/images/generations");
			log.debug({
				providerId: options.id,
				model: req.model,
				phase: isEdit ? "edit_request" : "generate_request",
				count,
				size
			}, `OpenAI-compatible ${isEdit ? "edit" : "generate"} request`);
			const responseJson = isEdit ? await postEditRequest({
				providerId: options.id,
				req,
				url,
				headers,
				count,
				size,
				httpDefaults,
				buildEditFormFields: options.buildEditFormFields
			}) : await postGenerateRequest({
				providerId: options.id,
				req,
				url,
				headers,
				count,
				size,
				httpDefaults,
				buildGenerateRequestBody: options.buildGenerateRequestBody
			});
			const mapped = (options.mapResponse ?? mapDefaultOpenAiResponse)(responseJson, req);
			if (mapped.length === 0) throw new Error(`${options.id} returned no images.`);
			return {
				images: mapped,
				model: req.model
			};
		}
	};
}
async function postGenerateRequest(params) {
	const baseBody = {
		model: params.req.model,
		prompt: params.req.prompt,
		n: params.count,
		size: params.size,
		response_format: "b64_json"
	};
	applyOpenAiOptions(baseBody, params.req);
	const body = params.buildGenerateRequestBody ? params.buildGenerateRequestBody(params.req, baseBody) : baseBody;
	const timeoutMs = pickTimeoutMsOrFallback(params.req.timeoutMs, params.httpDefaults.timeoutMs, DEFAULT_TIMEOUT_MS);
	return await (await postJsonRequest(params.url, {
		label: params.providerId,
		timeoutMs,
		signal: params.req.signal,
		body,
		headers: params.headers,
		...privateNetworkPolicyToSsrfGuardOptions()
	})).json();
}
async function postEditRequest(params) {
	const inputImages = params.req.inputImages ?? [];
	const fields = {
		model: params.req.model,
		prompt: params.req.prompt,
		n: String(params.count),
		size: params.size,
		response_format: "b64_json"
	};
	const merged = params.buildEditFormFields ? params.buildEditFormFields(params.req, fields) : fields;
	const form = new FormData();
	for (const [k, v] of Object.entries(merged)) if (typeof v === "string") form.append(k, v);
	for (let idx = 0; idx < inputImages.length; idx++) {
		const img = inputImages[idx];
		const field = idx === 0 ? "image" : `image[${idx}]`;
		const u8 = img.buffer instanceof Uint8Array ? img.buffer : new Uint8Array(img.buffer);
		const copy = new Uint8Array(u8.byteLength);
		copy.set(u8);
		form.append(field, new Blob([copy], { type: img.mimeType || DEFAULT_OUTPUT_MIME }), pickEditFileName(img, idx));
	}
	const headers = new Headers(params.headers);
	headers.delete("content-type");
	const timeoutMs = pickTimeoutMsOrFallback(params.req.timeoutMs, params.httpDefaults.timeoutMs, DEFAULT_TIMEOUT_MS);
	return await (await postMultipartRequest(params.url, {
		label: params.providerId,
		timeoutMs,
		signal: params.req.signal,
		body: form,
		headers,
		...privateNetworkPolicyToSsrfGuardOptions()
	})).json();
}
function mapDefaultOpenAiResponse(raw, req) {
	if (!raw || typeof raw !== "object") return [];
	const data = raw.data;
	if (!Array.isArray(data)) return [];
	const ext = imageFileExtensionForMimeType(req.outputFormat ? `image/${req.outputFormat}` : DEFAULT_OUTPUT_MIME);
	const out = [];
	data.forEach((entry, index) => {
		const b64 = entry?.b64_json;
		if (typeof b64 !== "string" || b64.length === 0) return;
		const asset = imageAssetFromBase64({
			base64: b64,
			mimeType: req.outputFormat ? `image/${req.outputFormat}` : void 0,
			fileName: `image-${index + 1}.${ext}`
		});
		out.push({
			...asset,
			...typeof entry.revised_prompt === "string" ? { revisedPrompt: entry.revised_prompt } : {}
		});
	});
	return out;
}
function applyAuthorizationHeader(params) {
	const auth = params.endpoint.authorization ?? { kind: "bearer" };
	if (auth.kind === "none") return;
	if (!params.apiKey) return;
	if (auth.kind === "bearer") {
		params.headers["authorization"] = `Bearer ${params.apiKey}`;
		return;
	}
	if (auth.kind === "header") params.headers[auth.headerName.toLowerCase()] = params.apiKey;
}
function applyOpenAiOptions(body, req) {
	if (req.quality) body.quality = req.quality;
	if (req.outputFormat) body.output_format = req.outputFormat;
	if (req.background) body.background = req.background;
	const opts = req.providerOptions?.openai;
	if (!opts) return;
	if (opts.moderation) body.moderation = opts.moderation;
	if (typeof opts.outputCompression === "number") body.output_compression = opts.outputCompression;
	if (typeof opts.user === "string" && opts.user) body.user = opts.user;
	if (opts.background && !body.background) body.background = opts.background;
}
function pickEditFileName(img, idx) {
	const safe = img.fileName?.trim().replace(/[^\w.-]/g, "_");
	if (safe) return safe;
	const ext = imageFileExtensionForMimeType(img.mimeType);
	return `image-${idx + 1}.${ext}`;
}
function clampCount(requested, fallback, max) {
	if (typeof requested !== "number" || !Number.isFinite(requested) || requested <= 0) return fallback;
	return Math.min(max, Math.max(1, Math.floor(requested)));
}
function joinPath(baseUrl, subPath) {
	return `${baseUrl.replace(/\/+$/, "")}${subPath.startsWith("/") ? subPath : `/${subPath}`}`;
}
//#endregion
export { createOpenAiCompatibleImageProvider, mapDefaultOpenAiResponse };

//# sourceMappingURL=openai-compatible-image-provider.js.map