import { logger } from "../preview/logger.js";

//#region src/elements/renderTemporalAudio.ts
async function renderTemporalAudio(host, fromMs, toMs, signal) {
	const aacFrames = 48e3 * ((toMs - fromMs) / 1e3) / 1024;
	const contextSize = Math.round(aacFrames) * 1024;
	if (contextSize <= 0) throw new Error(`Duration must be greater than 0 when rendering audio. ${contextSize}ms`);
	signal?.throwIfAborted();
	const audioContext = new OfflineAudioContext(2, contextSize, 48e3);
	if (host.waitForMediaDurations) {
		await host.waitForMediaDurations();
		signal?.throwIfAborted();
	}
	const mediaElements = host.getMediaElements();
	logger.debug(`[renderTemporalAudio] Found ${mediaElements.length} media elements, time range: ${fromMs}-${toMs}ms`);
	await Promise.all(mediaElements.map(async (mediaElement) => {
		logger.debug(`[renderTemporalAudio] Checking ${mediaElement.tagName} at ${mediaElement.startTimeMs}-${mediaElement.endTimeMs}ms, mute=${mediaElement.mute}`);
		if (mediaElement.mute) return;
		const mediaStartsBeforeEnd = mediaElement.startTimeMs <= toMs;
		const mediaEndsAfterStart = mediaElement.endTimeMs >= fromMs;
		if (!(mediaStartsBeforeEnd && mediaEndsAfterStart)) {
			logger.debug(`[renderTemporalAudio] ${mediaElement.tagName} does not overlap`);
			return;
		}
		const mediaLocalFromMs = Math.max(0, fromMs - mediaElement.startTimeMs);
		const mediaLocalToMs = Math.min(mediaElement.endTimeMs - mediaElement.startTimeMs, toMs - mediaElement.startTimeMs);
		if (mediaLocalFromMs >= mediaLocalToMs) return;
		const sourceInMs = mediaElement.sourceInMs || mediaElement.trimStartMs || 0;
		const mediaSourceFromMs = mediaLocalFromMs + sourceInMs;
		const mediaSourceToMs = mediaLocalToMs + sourceInMs;
		signal?.throwIfAborted();
		logger.debug(`[renderTemporalAudio] Fetching audio for ${mediaElement.tagName} from ${mediaSourceFromMs}-${mediaSourceToMs}ms`);
		const audio = await mediaElement.fetchAudioSpanningTime(mediaSourceFromMs, mediaSourceToMs, signal);
		if (!audio) {
			logger.debug(`[renderTemporalAudio] No audio returned for ${mediaElement.tagName}`);
			return;
		}
		logger.debug(`[renderTemporalAudio] Got audio blob size: ${audio.blob.size}, range: ${audio.startMs}-${audio.endMs}ms`);
		const bufferSource = audioContext.createBufferSource();
		let decodedBuffer;
		try {
			const arrayBuffer = await audio.blob.arrayBuffer();
			if (arrayBuffer.byteLength < 100) return;
			decodedBuffer = await audioContext.decodeAudioData(arrayBuffer);
		} catch (decodeError) {
			if (decodeError instanceof Error && decodeError.message.includes("Unable to decode audio data")) return;
			throw decodeError;
		}
		bufferSource.buffer = decodedBuffer;
		bufferSource.connect(audioContext.destination);
		const ctxStartMs = Math.max(0, mediaElement.startTimeMs - fromMs);
		const offsetInBufferMs = mediaSourceFromMs - audio.startMs;
		const safeOffsetMs = Math.max(0, offsetInBufferMs);
		const requestedDurationMs = mediaSourceToMs - mediaSourceFromMs;
		const availableAudioMs = audio.endMs - audio.startMs;
		const actualDurationMs = Math.min(requestedDurationMs, availableAudioMs - safeOffsetMs);
		if (actualDurationMs <= 0) return;
		bufferSource.start(ctxStartMs / 1e3, safeOffsetMs / 1e3, actualDurationMs / 1e3);
	}));
	return audioContext.startRendering();
}

//#endregion
export { renderTemporalAudio };
//# sourceMappingURL=renderTemporalAudio.js.map