import { getLatestMediaEngine } from "../tasks/makeMediaEngineTask.js";
import { ScrubInputCache } from "./ScrubInputCache.js";
import { Task } from "@lit/task";
const scrubInputCache = new ScrubInputCache();
const makeUnifiedVideoSeekTask = (host) => {
	return new Task(host, {
		args: () => [host.desiredSeekTimeMs],
		onError: (error) => {
			console.error("unifiedVideoSeekTask error", error);
		},
		onComplete: (_value) => {},
		task: async ([desiredSeekTimeMs], { signal }) => {
			signal.throwIfAborted();
			const mediaEngine = await getLatestMediaEngine(host, signal);
			if (!mediaEngine) return void 0;
			const mainRendition = mediaEngine.videoRendition;
			if (mainRendition) {
				const mainSegmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, mainRendition);
				if (mainSegmentId !== void 0 && mediaEngine.isSegmentCached(mainSegmentId, mainRendition)) return await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
			}
			const scrubSample = await tryGetScrubSample(mediaEngine, desiredSeekTimeMs, signal);
			if (scrubSample || signal.aborted) {
				if (scrubSample) startMainQualityUpgrade(host, mediaEngine, desiredSeekTimeMs, signal).catch(() => {});
				return scrubSample;
			}
			return await getMainVideoSample(host, mediaEngine, desiredSeekTimeMs, signal);
		}
	});
};
/**
* Try to get scrub sample from cache (instant if available)
*/
async function tryGetScrubSample(mediaEngine, desiredSeekTimeMs, signal) {
	try {
		let scrubRendition;
		if ("data" in mediaEngine && mediaEngine.data?.videoRenditions) scrubRendition = mediaEngine.data.videoRenditions.find((r) => r.id === "scrub");
		if (!scrubRendition) return void 0;
		const scrubRenditionWithSrc = {
			...scrubRendition,
			src: mediaEngine.src
		};
		const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, scrubRenditionWithSrc);
		if (segmentId === void 0) return void 0;
		const isCached = mediaEngine.isSegmentCached(segmentId, scrubRenditionWithSrc);
		if (!isCached) return void 0;
		const scrubInput = await scrubInputCache.getOrCreateInput(segmentId, async () => {
			const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(scrubRenditionWithSrc, signal), mediaEngine.fetchMediaSegment(segmentId, scrubRenditionWithSrc)]);
			if (!initSegment || !mediaSegment || signal.aborted) return void 0;
			const { BufferedSeekingInput } = await import("../BufferedSeekingInput.js");
			const { EFMedia } = await import("../../EFMedia.js");
			return new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
				videoBufferSize: EFMedia.VIDEO_SAMPLE_BUFFER_SIZE,
				audioBufferSize: EFMedia.AUDIO_SAMPLE_BUFFER_SIZE,
				startTimeOffsetMs: scrubRendition.startTimeOffsetMs
			});
		});
		if (!scrubInput) return void 0;
		const videoTrack = await scrubInput.getFirstVideoTrack();
		if (!videoTrack) return void 0;
		const sample = await scrubInput.seek(videoTrack.id, desiredSeekTimeMs);
		return sample;
	} catch (_error) {
		if (signal.aborted) return void 0;
		return void 0;
	}
}
/**
* Get main video sample (slower path with fetching)
*/
async function getMainVideoSample(_host, mediaEngine, desiredSeekTimeMs, signal) {
	try {
		const segmentId = mediaEngine.computeSegmentId(desiredSeekTimeMs, mediaEngine.getVideoRendition());
		if (segmentId === void 0) return void 0;
		const [initSegment, mediaSegment] = await Promise.all([mediaEngine.fetchInitSegment(mediaEngine.getVideoRendition(), signal), mediaEngine.fetchMediaSegment(segmentId, mediaEngine.getVideoRendition(), signal)]);
		if (!initSegment || !mediaSegment) return void 0;
		signal.throwIfAborted();
		const { BufferedSeekingInput } = await import("../BufferedSeekingInput.js");
		const { EFMedia } = await import("../../EFMedia.js");
		const videoRendition = mediaEngine.videoRendition;
		const startTimeOffsetMs = videoRendition?.startTimeOffsetMs;
		const mainInput = new BufferedSeekingInput(await new Blob([initSegment, mediaSegment]).arrayBuffer(), {
			videoBufferSize: EFMedia.VIDEO_SAMPLE_BUFFER_SIZE,
			audioBufferSize: EFMedia.AUDIO_SAMPLE_BUFFER_SIZE,
			startTimeOffsetMs
		});
		const videoTrack = await mainInput.getFirstVideoTrack();
		if (!videoTrack) return void 0;
		signal.throwIfAborted();
		const sample = await mainInput.seek(videoTrack.id, desiredSeekTimeMs);
		return sample;
	} catch (error) {
		if (signal.aborted) return void 0;
		throw error;
	}
}
/**
* Start background upgrade to main quality (non-blocking)
*/
async function startMainQualityUpgrade(host, mediaEngine, targetSeekTimeMs, signal) {
	await new Promise((resolve) => setTimeout(resolve, 50));
	if (signal.aborted || host.desiredSeekTimeMs !== targetSeekTimeMs) return;
	const mainSample = await getMainVideoSample(host, mediaEngine, targetSeekTimeMs, signal);
	if (mainSample && !signal.aborted && host.desiredSeekTimeMs === targetSeekTimeMs) {
		const videoFrame = mainSample.toVideoFrame();
		try {
			host.displayFrame(videoFrame, targetSeekTimeMs);
		} finally {
			videoFrame.close();
		}
	}
}
export { makeUnifiedVideoSeekTask };
