import type {ChromiumOptions, LogLevel} from '@remotion/renderer';
import {RenderInternals} from '@remotion/renderer';
import {BrowserSafeApis} from '@remotion/renderer/client';
import {NoReactInternals} from 'remotion/no-react';
import {defaultBrowserDownloadProgress} from './browser-download-bar';
import {registerCleanupJob} from './cleanup-before-quit';
import {getRendererPortFromConfigFileAndCliFlag} from './config/preview-server';
import {findEntryPoint} from './entry-point';
import {getCliOptions} from './get-cli-options';
import {Log} from './log';
import {parsedCli, quietFlagProvided} from './parsed-cli';
import {printCompositions} from './print-compositions';
import {bundleOnCliOrTakeServeUrl} from './setup-cache';

const {
	enableMultiprocessOnLinuxOption,
	offthreadVideoCacheSizeInBytesOption,
	offthreadVideoThreadsOption,
	glOption,
	headlessOption,
	delayRenderTimeoutInMillisecondsOption,
	binariesDirectoryOption,
	publicPathOption,
	publicDirOption,
	chromeModeOption,
	audioLatencyHintOption,
	mediaCacheSizeInBytesOption,
	darkModeOption,
	askAIOption,
	experimentalClientSideRenderingOption,
	experimentalVisualModeOption,
	keyboardShortcutsOption,
	rspackOption,
	browserExecutableOption,
	userAgentOption,
	disableWebSecurityOption,
	ignoreCertificateErrorsOption,
	bundleCacheOption,
} = BrowserSafeApis.options;

export const listCompositionsCommand = async (
	remotionRoot: string,
	args: string[],
	logLevel: LogLevel,
) => {
	const {file, reason} = findEntryPoint({
		args,
		remotionRoot,
		logLevel,
		allowDirectory: true,
	});

	if (!file) {
		Log.error(
			{indent: false, logLevel},
			'The `compositions` command requires you to specify a entry point. For example',
		);
		Log.error(
			{indent: false, logLevel},
			'  npx remotion compositions src/index.ts',
		);
		Log.error(
			{indent: false, logLevel},
			'See https://www.remotion.dev/docs/register-root for more information.',
		);
		process.exit(1);
	}

	Log.verbose(
		{indent: false, logLevel},
		'Entry point:',
		file,
		'reason:',
		reason,
	);

	const {envVariables, inputProps} = getCliOptions({
		isStill: false,
		logLevel,
		indent: false,
	});

	const browserExecutable = browserExecutableOption.getValue({
		commandLine: parsedCli,
	}).value;
	const userAgent = userAgentOption.getValue({commandLine: parsedCli}).value;
	const disableWebSecurity = disableWebSecurityOption.getValue({
		commandLine: parsedCli,
	}).value;
	const ignoreCertificateErrors = ignoreCertificateErrorsOption.getValue({
		commandLine: parsedCli,
	}).value;
	const publicPath = publicPathOption.getValue({commandLine: parsedCli}).value;
	const timeoutInMilliseconds = delayRenderTimeoutInMillisecondsOption.getValue(
		{
			commandLine: parsedCli,
		},
	).value;
	const binariesDirectory = binariesDirectoryOption.getValue({
		commandLine: parsedCli,
	}).value;
	const darkMode = darkModeOption.getValue({commandLine: parsedCli}).value;
	const offthreadVideoCacheSizeInBytes =
		offthreadVideoCacheSizeInBytesOption.getValue({
			commandLine: parsedCli,
		}).value;
	const offthreadVideoThreads = offthreadVideoThreadsOption.getValue({
		commandLine: parsedCli,
	}).value;
	const publicDir = publicDirOption.getValue({commandLine: parsedCli}).value;
	const chromeMode = chromeModeOption.getValue({
		commandLine: parsedCli,
	}).value;
	const audioLatencyHint = audioLatencyHintOption.getValue({
		commandLine: parsedCli,
	}).value;
	const mediaCacheSizeInBytes = mediaCacheSizeInBytesOption.getValue({
		commandLine: parsedCli,
	}).value;
	const askAIEnabled = askAIOption.getValue({commandLine: parsedCli}).value;

	const chromiumOptions: Required<ChromiumOptions> = {
		disableWebSecurity,
		enableMultiProcessOnLinux: enableMultiprocessOnLinuxOption.getValue({
			commandLine: parsedCli,
		}).value,
		gl: glOption.getValue({commandLine: parsedCli}).value,
		headless: headlessOption.getValue({commandLine: parsedCli}).value,
		ignoreCertificateErrors,
		userAgent,
		darkMode,
	};

	const experimentalClientSideRenderingEnabled =
		experimentalClientSideRenderingOption.getValue({
			commandLine: parsedCli,
		}).value;
	const experimentalVisualModeEnabled = experimentalVisualModeOption.getValue({
		commandLine: parsedCli,
	}).value;
	const keyboardShortcutsEnabled = keyboardShortcutsOption.getValue({
		commandLine: parsedCli,
	}).value;
	const rspack = rspackOption.getValue({commandLine: parsedCli}).value;
	const shouldCache = bundleCacheOption.getValue({
		commandLine: parsedCli,
	}).value;

	if (experimentalClientSideRenderingEnabled) {
		Log.warn(
			{indent: false, logLevel},
			'Enabling WIP client-side rendering. Please see caveats on https://www.remotion.dev/docs/client-side-rendering/.',
		);
	}

	const {urlOrBundle: bundled, cleanup: cleanupBundle} =
		await bundleOnCliOrTakeServeUrl({
			remotionRoot,
			fullPath: file,
			publicDir,
			onProgress: () => undefined,
			indentOutput: false,
			logLevel,
			onDirectoryCreated: (dir) => {
				registerCleanupJob(`Delete ${dir}`, () =>
					RenderInternals.deleteDirectory(dir),
				);
			},
			quietProgress: false,
			quietFlag: quietFlagProvided(),
			outDir: null,
			// Not needed for compositions
			gitSource: null,
			bufferStateDelayInMilliseconds: null,
			maxTimelineTracks: null,
			publicPath,
			audioLatencyHint,
			experimentalClientSideRenderingEnabled,
			experimentalVisualModeEnabled,
			askAIEnabled,
			keyboardShortcutsEnabled,
			rspack,
			shouldCache,
		});

	registerCleanupJob(`Cleanup bundle`, () => cleanupBundle());

	const compositions = await RenderInternals.internalGetCompositions({
		serveUrlOrWebpackUrl: bundled,
		browserExecutable,
		chromiumOptions,
		envVariables,
		serializedInputPropsWithCustomSchema:
			NoReactInternals.serializeJSONWithSpecialTypes({
				data: inputProps,
				staticBase: null,
				indent: undefined,
			}).serializedString,
		timeoutInMilliseconds,
		port: getRendererPortFromConfigFileAndCliFlag(),
		indent: false,
		onBrowserLog: null,
		puppeteerInstance: undefined,
		logLevel,
		server: undefined,
		offthreadVideoCacheSizeInBytes,
		offthreadVideoThreads,
		binariesDirectory,
		onBrowserDownload: defaultBrowserDownloadProgress({
			indent: false,
			logLevel,
			quiet: quietFlagProvided(),
			onProgress: () => undefined,
		}),
		chromeMode,
		mediaCacheSizeInBytes,
		onLog: RenderInternals.defaultOnLog,
	});

	printCompositions(compositions, logLevel);
};
