import { t as createSubsystemLogger } from "./subsystem-BtFUtQCl.js";
import { c as resolveClosestAspectRatio, d as throwCapabilityGenerationFailure, i as hasMediaNormalizationEntry, l as resolveClosestResolution, n as buildNoCapabilityModelConfiguredMessage, o as recordCapabilityCandidateFailure, s as resolveCapabilityModelCandidates, t as buildMediaGenerationNormalizationMetadata, u as resolveClosestSize } from "./runtime-shared-D-kcYAxZ.js";
import { a as resolveVideoGenerationModeCapabilities, n as resolveVideoGenerationSupportedDurations, t as normalizeVideoGenerationDuration } from "./duration-support-BmSUoRbh.js";
import { t as parseVideoGenerationModelRef } from "./model-ref-BSNL7Z1P.js";
import { n as listVideoGenerationProviders, t as getVideoGenerationProvider } from "./provider-registry-DalrzAab.js";
//#region src/video-generation/normalization.ts
function resolveVideoGenerationOverrides(params) {
	const { capabilities: caps } = resolveVideoGenerationModeCapabilities({
		provider: params.provider,
		model: params.model,
		inputImageCount: params.inputImageCount,
		inputVideoCount: params.inputVideoCount
	});
	const ignoredOverrides = [];
	const normalization = {};
	let size = params.size;
	let aspectRatio = params.aspectRatio;
	let resolution = params.resolution;
	let audio = params.audio;
	let watermark = params.watermark;
	if (caps) {
		if (size && (caps.sizes?.length ?? 0) > 0 && caps.supportsSize) {
			const normalizedSize = resolveClosestSize({
				requestedSize: size,
				requestedAspectRatio: aspectRatio,
				supportedSizes: caps.sizes
			});
			if (normalizedSize && normalizedSize !== size) normalization.size = {
				requested: size,
				applied: normalizedSize
			};
			size = normalizedSize;
		}
		if (!caps.supportsSize && size) {
			let translated = false;
			if (caps.supportsAspectRatio) {
				const normalizedAspectRatio = resolveClosestAspectRatio({
					requestedAspectRatio: aspectRatio,
					requestedSize: size,
					supportedAspectRatios: caps.aspectRatios
				});
				if (normalizedAspectRatio) {
					aspectRatio = normalizedAspectRatio;
					normalization.aspectRatio = {
						applied: normalizedAspectRatio,
						derivedFrom: "size"
					};
					translated = true;
				}
			}
			if (!translated) ignoredOverrides.push({
				key: "size",
				value: size
			});
			size = void 0;
		}
		if (aspectRatio && (caps.aspectRatios?.length ?? 0) > 0 && caps.supportsAspectRatio) {
			const normalizedAspectRatio = resolveClosestAspectRatio({
				requestedAspectRatio: aspectRatio,
				requestedSize: size,
				supportedAspectRatios: caps.aspectRatios
			});
			if (normalizedAspectRatio && normalizedAspectRatio !== aspectRatio) normalization.aspectRatio = {
				requested: aspectRatio,
				applied: normalizedAspectRatio
			};
			else if (!normalizedAspectRatio) ignoredOverrides.push({
				key: "aspectRatio",
				value: aspectRatio
			});
			aspectRatio = normalizedAspectRatio;
		} else if (!caps.supportsAspectRatio && aspectRatio) {
			const derivedSize = caps.supportsSize && !size ? resolveClosestSize({
				requestedSize: params.size,
				requestedAspectRatio: aspectRatio,
				supportedSizes: caps.sizes
			}) : void 0;
			if (derivedSize) {
				size = derivedSize;
				normalization.size = {
					applied: derivedSize,
					derivedFrom: "aspectRatio"
				};
			} else ignoredOverrides.push({
				key: "aspectRatio",
				value: aspectRatio
			});
			aspectRatio = void 0;
		}
		if (resolution && (caps.resolutions?.length ?? 0) > 0 && caps.supportsResolution) {
			const normalizedResolution = resolveClosestResolution({
				requestedResolution: resolution,
				supportedResolutions: caps.resolutions
			});
			if (normalizedResolution && normalizedResolution !== resolution) normalization.resolution = {
				requested: resolution,
				applied: normalizedResolution
			};
			resolution = normalizedResolution;
		} else if (resolution && !caps.supportsResolution) {
			ignoredOverrides.push({
				key: "resolution",
				value: resolution
			});
			resolution = void 0;
		}
		if (typeof audio === "boolean" && !caps.supportsAudio) {
			ignoredOverrides.push({
				key: "audio",
				value: audio
			});
			audio = void 0;
		}
		if (typeof watermark === "boolean" && !caps.supportsWatermark) {
			ignoredOverrides.push({
				key: "watermark",
				value: watermark
			});
			watermark = void 0;
		}
	}
	if (caps && size && !caps.supportsSize) {
		ignoredOverrides.push({
			key: "size",
			value: size
		});
		size = void 0;
	}
	if (caps && aspectRatio && !caps.supportsAspectRatio) {
		ignoredOverrides.push({
			key: "aspectRatio",
			value: aspectRatio
		});
		aspectRatio = void 0;
	}
	if (caps && resolution && !caps.supportsResolution) {
		ignoredOverrides.push({
			key: "resolution",
			value: resolution
		});
		resolution = void 0;
	}
	if (!normalization.size && size && params.size && params.size !== size) normalization.size = {
		requested: params.size,
		applied: size
	};
	if (!normalization.aspectRatio && aspectRatio && (!params.aspectRatio && params.size || params.aspectRatio !== aspectRatio)) normalization.aspectRatio = {
		applied: aspectRatio,
		...params.aspectRatio ? { requested: params.aspectRatio } : {},
		...!params.aspectRatio && params.size ? { derivedFrom: "size" } : {}
	};
	if (!normalization.resolution && resolution && params.resolution && params.resolution !== resolution) normalization.resolution = {
		requested: params.resolution,
		applied: resolution
	};
	const requestedDurationSeconds = typeof params.durationSeconds === "number" && Number.isFinite(params.durationSeconds) ? Math.max(1, Math.round(params.durationSeconds)) : void 0;
	const durationSeconds = normalizeVideoGenerationDuration({
		provider: params.provider,
		model: params.model,
		durationSeconds: requestedDurationSeconds,
		inputImageCount: params.inputImageCount ?? 0,
		inputVideoCount: params.inputVideoCount ?? 0
	});
	const supportedDurationSeconds = resolveVideoGenerationSupportedDurations({
		provider: params.provider,
		model: params.model,
		inputImageCount: params.inputImageCount ?? 0,
		inputVideoCount: params.inputVideoCount ?? 0
	});
	if (typeof requestedDurationSeconds === "number" && typeof durationSeconds === "number" && requestedDurationSeconds !== durationSeconds) normalization.durationSeconds = {
		requested: requestedDurationSeconds,
		applied: durationSeconds,
		...supportedDurationSeconds?.length ? { supportedValues: supportedDurationSeconds } : {}
	};
	return {
		size,
		aspectRatio,
		resolution,
		durationSeconds,
		supportedDurationSeconds,
		audio,
		watermark,
		ignoredOverrides,
		normalization: hasMediaNormalizationEntry(normalization.size) || hasMediaNormalizationEntry(normalization.aspectRatio) || hasMediaNormalizationEntry(normalization.resolution) || hasMediaNormalizationEntry(normalization.durationSeconds) ? normalization : void 0
	};
}
//#endregion
//#region src/video-generation/runtime.ts
const log = createSubsystemLogger("video-generation");
/**
* Validate agent-supplied providerOptions against the candidate's declared
* schema. Returns a human-readable skip reason when the candidate cannot
* accept the supplied options, or undefined when everything checks out.
*
* Backward-compatible behavior:
* - Provider declares no schema (undefined): pass options through as-is.
*   The provider receives them and may silently ignore unknown keys. This is
*   the safe default for legacy / not-yet-migrated providers.
* - Provider explicitly declares an empty schema ({}): rejects any options.
*   This is the opt-in signal that the provider has been audited and truly
*   supports no options.
* - Provider declares a typed schema: validates each key name and value type,
*   skipping the candidate on any mismatch.
*/
function validateProviderOptionsAgainstDeclaration(params) {
	const { providerId, model, providerOptions, declaration } = params;
	const keys = Object.keys(providerOptions);
	if (keys.length === 0) return;
	if (declaration === void 0) return;
	if (Object.keys(declaration).length === 0) return `${providerId}/${model} does not accept providerOptions (caller supplied: ${keys.join(", ")}); skipping`;
	const unknown = keys.filter((key) => !Object.hasOwn(declaration, key));
	if (unknown.length > 0) {
		const accepted = Object.keys(declaration).join(", ");
		return `${providerId}/${model} does not accept providerOptions keys: ${unknown.join(", ")} (accepted: ${accepted}); skipping`;
	}
	for (const key of keys) {
		const expected = declaration[key];
		const value = providerOptions[key];
		const actual = typeof value;
		if (expected === "number" && (actual !== "number" || !Number.isFinite(value))) return `${providerId}/${model} expects providerOptions.${key} to be a finite number, got ${actual}; skipping`;
		if (expected === "boolean" && actual !== "boolean") return `${providerId}/${model} expects providerOptions.${key} to be a boolean, got ${actual}; skipping`;
		if (expected === "string" && actual !== "string") return `${providerId}/${model} expects providerOptions.${key} to be a string, got ${actual}; skipping`;
	}
}
function buildNoVideoGenerationModelConfiguredMessage(cfg, deps) {
	return buildNoCapabilityModelConfiguredMessage({
		capabilityLabel: "video-generation",
		modelConfigKey: "videoGenerationModel",
		providers: (deps.listProviders ?? listVideoGenerationProviders)(cfg),
		getProviderEnvVars: deps.getProviderEnvVars
	});
}
function listRuntimeVideoGenerationProviders(params, deps = {}) {
	return (deps.listProviders ?? listVideoGenerationProviders)(params?.config);
}
async function generateVideo(params, deps = {}) {
	const getProvider = deps.getProvider ?? getVideoGenerationProvider;
	const listProviders = deps.listProviders ?? listVideoGenerationProviders;
	const logger = deps.log ?? log;
	const candidates = resolveCapabilityModelCandidates({
		cfg: params.cfg,
		modelConfig: params.cfg.agents?.defaults?.videoGenerationModel,
		modelOverride: params.modelOverride,
		parseModelRef: parseVideoGenerationModelRef,
		agentDir: params.agentDir,
		listProviders
	});
	if (candidates.length === 0) throw new Error(buildNoVideoGenerationModelConfiguredMessage(params.cfg, deps));
	const attempts = [];
	let lastError;
	let skipWarnEmitted = false;
	const warnOnFirstSkip = (reason) => {
		if (!skipWarnEmitted) {
			skipWarnEmitted = true;
			logger.warn(`video-generation candidate skipped: ${reason}`);
		}
	};
	for (const candidate of candidates) {
		const provider = getProvider(candidate.provider, params.cfg);
		if (!provider) {
			const error = `No video-generation provider registered for ${candidate.provider}`;
			attempts.push({
				provider: candidate.provider,
				model: candidate.model,
				error
			});
			lastError = new Error(error);
			continue;
		}
		const inputImageCount = params.inputImages?.length ?? 0;
		const inputVideoCount = params.inputVideos?.length ?? 0;
		const inputAudioCount = params.inputAudios?.length ?? 0;
		if (inputAudioCount > 0) {
			const { capabilities: candCaps } = resolveVideoGenerationModeCapabilities({
				provider,
				model: candidate.model,
				inputImageCount,
				inputVideoCount
			});
			const maxAudio = candCaps?.maxInputAudios ?? provider.capabilities.maxInputAudios ?? 0;
			if (inputAudioCount > maxAudio) {
				const error = maxAudio === 0 ? `${candidate.provider}/${candidate.model} does not support reference audio inputs; skipping to avoid silent audio drop` : `${candidate.provider}/${candidate.model} supports at most ${maxAudio} reference audio(s), ${inputAudioCount} requested; skipping`;
				attempts.push({
					provider: candidate.provider,
					model: candidate.model,
					error
				});
				lastError = new Error(error);
				warnOnFirstSkip(error);
				logger.debug(`video-generation candidate skipped (audio capability): ${candidate.provider}/${candidate.model}`);
				continue;
			}
		}
		if (params.providerOptions && typeof params.providerOptions === "object" && Object.keys(params.providerOptions).length > 0) {
			const { capabilities: optCaps } = resolveVideoGenerationModeCapabilities({
				provider,
				model: candidate.model,
				inputImageCount,
				inputVideoCount
			});
			const declaredOptions = optCaps?.providerOptions ?? provider.capabilities.providerOptions ?? void 0;
			const mismatch = validateProviderOptionsAgainstDeclaration({
				providerId: candidate.provider,
				model: candidate.model,
				providerOptions: params.providerOptions,
				declaration: declaredOptions
			});
			if (mismatch) {
				attempts.push({
					provider: candidate.provider,
					model: candidate.model,
					error: mismatch
				});
				lastError = new Error(mismatch);
				warnOnFirstSkip(mismatch);
				logger.debug(`video-generation candidate skipped (providerOptions): ${candidate.provider}/${candidate.model}`);
				continue;
			}
		}
		const requestedDuration = params.durationSeconds;
		if (typeof requestedDuration === "number" && Number.isFinite(requestedDuration)) {
			const { capabilities: durCaps } = resolveVideoGenerationModeCapabilities({
				provider,
				model: candidate.model,
				inputImageCount,
				inputVideoCount
			});
			const supportedDurations = resolveVideoGenerationSupportedDurations({
				provider,
				model: candidate.model,
				inputImageCount,
				inputVideoCount
			});
			const maxDuration = durCaps?.maxDurationSeconds ?? provider.capabilities.maxDurationSeconds;
			if (!supportedDurations && typeof maxDuration === "number" && Math.round(requestedDuration) > maxDuration) {
				const error = `${candidate.provider}/${candidate.model} supports at most ${maxDuration}s per video, ${requestedDuration}s requested; skipping`;
				attempts.push({
					provider: candidate.provider,
					model: candidate.model,
					error
				});
				lastError = new Error(error);
				warnOnFirstSkip(error);
				logger.debug(`video-generation candidate skipped (duration capability): ${candidate.provider}/${candidate.model}`);
				continue;
			}
		}
		try {
			const sanitized = resolveVideoGenerationOverrides({
				provider,
				model: candidate.model,
				size: params.size,
				aspectRatio: params.aspectRatio,
				resolution: params.resolution,
				durationSeconds: params.durationSeconds,
				audio: params.audio,
				watermark: params.watermark,
				inputImageCount,
				inputVideoCount
			});
			const result = await provider.generateVideo({
				provider: candidate.provider,
				model: candidate.model,
				prompt: params.prompt,
				cfg: params.cfg,
				agentDir: params.agentDir,
				authStore: params.authStore,
				size: sanitized.size,
				aspectRatio: sanitized.aspectRatio,
				resolution: sanitized.resolution,
				durationSeconds: sanitized.durationSeconds,
				audio: sanitized.audio,
				watermark: sanitized.watermark,
				inputImages: params.inputImages,
				inputVideos: params.inputVideos,
				inputAudios: params.inputAudios,
				providerOptions: params.providerOptions,
				...params.timeoutMs !== void 0 ? { timeoutMs: params.timeoutMs } : {}
			});
			if (!Array.isArray(result.videos) || result.videos.length === 0) throw new Error("Video generation provider returned no videos.");
			for (const [index, video] of result.videos.entries()) if (!video.buffer && !video.url) throw new Error(`Video generation provider returned an undeliverable asset at index ${index}: neither buffer nor url is set.`);
			return {
				videos: result.videos,
				provider: candidate.provider,
				model: result.model ?? candidate.model,
				attempts,
				normalization: sanitized.normalization,
				ignoredOverrides: sanitized.ignoredOverrides,
				metadata: {
					...result.metadata,
					...buildMediaGenerationNormalizationMetadata({
						normalization: sanitized.normalization,
						requestedSizeForDerivedAspectRatio: params.size,
						includeSupportedDurationSeconds: true
					})
				}
			};
		} catch (err) {
			lastError = err;
			recordCapabilityCandidateFailure({
				attempts,
				provider: candidate.provider,
				model: candidate.model,
				error: err
			});
			logger.debug(`video-generation candidate failed: ${candidate.provider}/${candidate.model}`);
		}
	}
	return throwCapabilityGenerationFailure({
		capabilityLabel: "video generation",
		attempts,
		lastError
	});
}
//#endregion
export { listRuntimeVideoGenerationProviders as n, generateVideo as t };
