import {useContext, useState, useEffect} from 'react';
import type {LoopDisplay, SequenceControls} from 'remotion';
import {Internals, useCurrentFrame, type VolumeProp} from 'remotion';

export const useMediaInTimeline = ({
	volume,
	mediaVolume,
	src,
	mediaType,
	playbackRate,
	displayName,
	stack,
	showInTimeline,
	premountDisplay,
	postmountDisplay,
	loopDisplay,
	trimBefore,
	trimAfter,
	controls,
}: {
	volume: VolumeProp | undefined;
	mediaVolume: number;
	src: string | undefined;
	mediaType: 'audio' | 'video';
	playbackRate: number;
	displayName: string | null;
	stack: string | null;
	showInTimeline: boolean;
	premountDisplay: number | null;
	postmountDisplay: number | null;
	loopDisplay: LoopDisplay | undefined;
	trimBefore: number | undefined;
	trimAfter: number | undefined;
	controls: SequenceControls | undefined;
}) => {
	const parentSequence = useContext(Internals.SequenceContext);
	const startsAt = Internals.useMediaStartsAt();
	const {registerSequence, unregisterSequence} = useContext(
		Internals.SequenceManager,
	);

	const [sequenceId] = useState(() => String(Math.random()));
	const [mediaId] = useState(() => String(Math.random()));
	const frame = useCurrentFrame();

	const {
		volumes,
		duration,
		doesVolumeChange,
		nonce,
		rootId,
		isStudio,
		finalDisplayName,
	} = Internals.useBasicMediaInTimeline({
		volume,
		mediaVolume,
		mediaType,
		src,
		displayName,
		trimBefore,
		trimAfter,
		playbackRate,
	});

	useEffect(() => {
		if (!src) {
			throw new Error('No src passed');
		}

		if (!isStudio && window.process?.env?.NODE_ENV !== 'test') {
			return;
		}

		if (!showInTimeline) {
			return;
		}

		const loopIteration = loopDisplay
			? Math.floor(frame / loopDisplay.durationInFrames)
			: 0;

		if (loopDisplay) {
			registerSequence({
				type: 'sequence',
				premountDisplay,
				postmountDisplay,
				parent: parentSequence?.id ?? null,
				displayName: finalDisplayName,
				rootId,
				showInTimeline: true,
				nonce: nonce.get(),
				loopDisplay,
				stack,
				from: 0,
				duration,
				id: sequenceId,
				controls: null,
			});
		}

		registerSequence({
			type: mediaType,
			src,
			id: mediaId,
			duration: loopDisplay?.durationInFrames ?? duration,
			from: loopDisplay ? loopIteration * loopDisplay.durationInFrames : 0,
			parent: loopDisplay ? sequenceId : (parentSequence?.id ?? null),
			displayName: finalDisplayName,
			rootId,
			volume: volumes,
			showInTimeline: true,
			nonce: nonce.get(),
			startMediaFrom: 0 - startsAt + (trimBefore ?? 0),
			doesVolumeChange,
			loopDisplay: undefined,
			playbackRate,
			stack,
			premountDisplay: null,
			postmountDisplay: null,
			controls: controls ?? null,
		});

		return () => {
			if (loopDisplay) {
				unregisterSequence(sequenceId);
			}

			unregisterSequence(mediaId);
		};
	}, [
		controls,
		doesVolumeChange,
		duration,
		finalDisplayName,
		isStudio,
		loopDisplay,
		mediaId,
		mediaType,
		nonce,
		parentSequence?.id,
		playbackRate,
		postmountDisplay,
		premountDisplay,
		registerSequence,
		rootId,
		sequenceId,
		showInTimeline,
		src,
		stack,
		startsAt,
		unregisterSequence,
		volumes,
		frame,
		trimBefore,
	]);

	return {
		id: mediaId,
	};
};
