import { o as logger } from "./logger-CfDSdx1q.js";
import { n as sleep } from "./time-DpwT58mY.js";
import { a as storeBlob } from "./blobs-0KeBpJTF.js";
import { t as ellipsize } from "./text-CFa1rdK5.js";
import { t as AwsBedrockGenericProvider } from "./base-Dbweuox6.js";
import * as fs$1 from "fs";
import * as path$1 from "path";
//#region src/providers/bedrock/nova-reel.ts
/**
* Amazon Nova Reel Video Generation Provider
*
* Supports text-to-video and image-to-video generation using AWS Bedrock's
* async invoke API. Videos are generated in 6-second increments up to 2 minutes.
*/
const MODEL_ID = "amazon.nova-reel-v1:1";
const DEFAULT_DURATION_SECONDS = 6;
const DEFAULT_POLL_INTERVAL_MS = 1e4;
const DEFAULT_MAX_POLL_TIME_MS = 9e5;
const VIDEO_DIMENSION = "1280x720";
const VIDEO_FPS = 24;
var NovaReelVideoProvider = class extends AwsBedrockGenericProvider {
	videoConfig;
	providerId;
	constructor(modelName = MODEL_ID, options = {}) {
		super(modelName, options);
		this.videoConfig = options.config || {};
		this.providerId = options.id;
	}
	id() {
		return this.providerId || `bedrock:video:${this.modelName}`;
	}
	toString() {
		return `[Amazon Nova Reel Video Provider ${this.modelName}]`;
	}
	/**
	* Load image data from file:// path or return as-is if base64
	*/
	loadImageData(imagePath) {
		if (imagePath.startsWith("file://")) {
			const filePath = imagePath.slice(7);
			const resolvedPath = path$1.resolve(filePath);
			if (filePath.includes("..") && resolvedPath !== path$1.resolve(path$1.normalize(filePath))) return { error: `Invalid image path (path traversal detected): ${filePath}` };
			if (!fs$1.existsSync(resolvedPath)) return { error: `Image file not found: ${resolvedPath}` };
			return { data: fs$1.readFileSync(resolvedPath).toString("base64") };
		}
		return { data: imagePath };
	}
	/**
	* Detect image format from path or data
	*/
	detectImageFormat(imagePath) {
		const lowerPath = imagePath.toLowerCase();
		if (lowerPath.includes(".png") || lowerPath.startsWith("ivborw")) return "png";
		return "jpeg";
	}
	/**
	* Build model input based on task type
	*/
	buildModelInput(prompt, config) {
		const taskType = config.taskType || "TEXT_VIDEO";
		const durationSeconds = config.durationSeconds || DEFAULT_DURATION_SECONDS;
		if (taskType === "TEXT_VIDEO" && durationSeconds !== 6) return { error: "TEXT_VIDEO task type only supports durationSeconds: 6" };
		if ((taskType === "MULTI_SHOT_AUTOMATED" || taskType === "MULTI_SHOT_MANUAL") && (durationSeconds < 12 || durationSeconds > 120 || durationSeconds % 6 !== 0)) return { error: `Multi-shot videos require durationSeconds between 12-120 in multiples of 6. Got: ${durationSeconds}` };
		const videoGenerationConfig = {
			durationSeconds,
			fps: VIDEO_FPS,
			dimension: VIDEO_DIMENSION,
			...config.seed !== void 0 && { seed: config.seed }
		};
		if (taskType === "TEXT_VIDEO") {
			const textToVideoParams = { text: prompt };
			if (config.image) {
				const { data, error } = this.loadImageData(config.image);
				if (error) return { error };
				textToVideoParams.images = [{
					format: this.detectImageFormat(config.image),
					source: { bytes: data }
				}];
			}
			return { input: {
				taskType: "TEXT_VIDEO",
				textToVideoParams,
				videoGenerationConfig
			} };
		}
		if (taskType === "MULTI_SHOT_AUTOMATED") {
			if (prompt.length > 4e3) return { error: `MULTI_SHOT_AUTOMATED prompt exceeds 4000 character limit. Got: ${prompt.length}` };
			return { input: {
				taskType: "MULTI_SHOT_AUTOMATED",
				multiShotAutomatedParams: { text: prompt },
				videoGenerationConfig
			} };
		}
		if (taskType === "MULTI_SHOT_MANUAL") {
			if (!config.shots || config.shots.length === 0) return { error: "MULTI_SHOT_MANUAL requires shots array in config" };
			return { input: {
				taskType: "MULTI_SHOT_MANUAL",
				multiShotManualParams: { shots: config.shots.map((shot) => {
					const shotDef = { text: shot.text };
					if (shot.image) shotDef.image = shot.image;
					return shotDef;
				}) },
				videoGenerationConfig
			} };
		}
		return { error: `Unknown task type: ${taskType}` };
	}
	/**
	* Start async video generation job
	*/
	async startVideoGeneration(modelInput, s3OutputUri) {
		try {
			const { BedrockRuntimeClient, StartAsyncInvokeCommand } = await import("@aws-sdk/client-bedrock-runtime");
			const credentials = await this.getCredentials();
			const client = new BedrockRuntimeClient({
				region: this.getRegion(),
				...credentials ? { credentials } : {}
			});
			const command = new StartAsyncInvokeCommand({
				modelId: this.modelName,
				modelInput,
				outputDataConfig: { s3OutputDataConfig: { s3Uri: s3OutputUri } }
			});
			return { invocationArn: (await client.send(command)).invocationArn };
		} catch (err) {
			const error = err;
			logger.error("[Nova Reel] Failed to start video generation", { error });
			return { error: `Failed to start video generation: ${error.message || String(err)}` };
		}
	}
	/**
	* Poll for job completion
	*/
	async pollForCompletion(invocationArn, pollIntervalMs, maxPollTimeMs) {
		const startTime = Date.now();
		try {
			const { BedrockRuntimeClient, GetAsyncInvokeCommand } = await import("@aws-sdk/client-bedrock-runtime");
			const credentials = await this.getCredentials();
			const client = new BedrockRuntimeClient({
				region: this.getRegion(),
				...credentials ? { credentials } : {}
			});
			while (Date.now() - startTime < maxPollTimeMs) {
				const command = new GetAsyncInvokeCommand({ invocationArn });
				const invocation = await client.send(command);
				logger.debug(`[Nova Reel] Job status: ${invocation.status}`, {
					invocationArn,
					elapsedMs: Date.now() - startTime
				});
				if (invocation.status === "Completed") return { response: {
					invocationArn: invocation.invocationArn || invocationArn,
					status: "Completed",
					submitTime: invocation.submitTime?.toISOString(),
					endTime: invocation.endTime?.toISOString(),
					outputDataConfig: invocation.outputDataConfig
				} };
				if (invocation.status === "Failed") return { error: `Video generation failed: ${invocation.failureMessage}` };
				await sleep(pollIntervalMs);
			}
			return { error: `Video generation timed out after ${maxPollTimeMs / 1e3} seconds` };
		} catch (err) {
			const error = err;
			logger.error("[Nova Reel] Polling error", {
				error,
				invocationArn
			});
			return { error: `Polling error: ${error.message || String(err)}` };
		}
	}
	/**
	* Download video from S3 and store to blob storage
	*/
	async downloadAndStoreVideo(s3Uri) {
		try {
			const match = s3Uri.match(/^s3:\/\/([^/]+)\/(.+)$/);
			if (!match) return { error: `Invalid S3 URI: ${s3Uri}` };
			const [, bucket, keyPrefix] = match;
			const { S3Client, GetObjectCommand } = await import("@aws-sdk/client-s3");
			const credentials = await this.getCredentials();
			const s3 = new S3Client({
				region: this.getRegion(),
				...credentials ? { credentials } : {}
			});
			const videoKey = keyPrefix.endsWith("/") ? `${keyPrefix}output.mp4` : `${keyPrefix}/output.mp4`;
			logger.debug("[Nova Reel] Downloading video from S3", {
				bucket,
				key: videoKey
			});
			const response = await s3.send(new GetObjectCommand({
				Bucket: bucket,
				Key: videoKey
			}));
			if (!response.Body) return { error: "Empty response from S3" };
			const { ref } = await storeBlob(Buffer.from(await response.Body.transformToByteArray()), "video/mp4", {
				kind: "video",
				location: "response.video"
			});
			logger.debug(`[Nova Reel] Stored video to blob storage`, {
				uri: ref.uri,
				hash: ref.hash
			});
			return { blobRef: ref };
		} catch (err) {
			const error = err;
			logger.error("[Nova Reel] S3 download error", {
				error,
				s3Uri
			});
			if (error.name === "MODULE_NOT_FOUND" || String(err).includes("Cannot find module")) return { error: "The @aws-sdk/client-s3 package is required for Nova Reel video downloads. Install it with: npm install @aws-sdk/client-s3" };
			return { error: `S3 download error: ${error.message || String(err)}` };
		}
	}
	async callApi(prompt, context) {
		const s3OutputUri = this.videoConfig.s3OutputUri;
		if (!s3OutputUri) return { error: "Nova Reel requires s3OutputUri in provider config. Example: s3://my-bucket/videos" };
		if (!s3OutputUri.startsWith("s3://")) return { error: `Invalid s3OutputUri: ${s3OutputUri}. Must start with s3://` };
		if (!prompt || prompt.trim() === "") return { error: "Prompt is required for video generation" };
		const config = {
			...this.videoConfig,
			...context?.prompt?.config
		};
		const startTime = Date.now();
		const { input: modelInput, error: buildError } = this.buildModelInput(prompt, config);
		if (buildError || !modelInput) return { error: buildError || "Failed to build model input" };
		logger.info(`[Nova Reel] Starting video generation job...`, {
			taskType: config.taskType || "TEXT_VIDEO",
			durationSeconds: config.durationSeconds || DEFAULT_DURATION_SECONDS,
			s3OutputUri
		});
		const { invocationArn, error: startError } = await this.startVideoGeneration(modelInput, s3OutputUri);
		if (startError || !invocationArn) return { error: startError || "Failed to start video generation" };
		logger.info(`[Nova Reel] Job started`, { invocationArn });
		const pollIntervalMs = config.pollIntervalMs || DEFAULT_POLL_INTERVAL_MS;
		const maxPollTimeMs = config.maxPollTimeMs || DEFAULT_MAX_POLL_TIME_MS;
		const { response, error: pollError } = await this.pollForCompletion(invocationArn, pollIntervalMs, maxPollTimeMs);
		if (pollError || !response) return { error: pollError || "Polling failed" };
		const outputS3Uri = response.outputDataConfig?.s3OutputDataConfig?.s3Uri;
		if (!outputS3Uri) return { error: "No output location in response" };
		let blobRef;
		const outputUrl = `${outputS3Uri}/output.mp4`;
		if (config.downloadFromS3 !== false) {
			const { blobRef: ref, error: downloadError } = await this.downloadAndStoreVideo(outputS3Uri);
			if (downloadError) logger.warn(`[Nova Reel] Failed to download video: ${downloadError}. Using S3 URL.`);
			else blobRef = ref;
		}
		const latencyMs = Date.now() - startTime;
		const durationSeconds = config.durationSeconds || DEFAULT_DURATION_SECONDS;
		return {
			output: `[Video: ${ellipsize(prompt.replace(/\r?\n|\r/g, " ").replace(/\[/g, "(").replace(/\]/g, ")"), 50)}](${blobRef?.uri || outputUrl})`,
			cached: false,
			latencyMs,
			video: {
				id: invocationArn,
				blobRef,
				url: blobRef ? void 0 : outputUrl,
				format: "mp4",
				size: VIDEO_DIMENSION,
				duration: durationSeconds,
				model: this.modelName,
				resolution: VIDEO_DIMENSION
			},
			metadata: {
				invocationArn,
				model: this.modelName,
				taskType: config.taskType || "TEXT_VIDEO",
				durationSeconds,
				s3OutputUri: outputS3Uri,
				...blobRef && { blobHash: blobRef.hash }
			}
		};
	}
};
//#endregion
export { NovaReelVideoProvider };

//# sourceMappingURL=nova-reel-BEF1yhaN.js.map