/**
 * @deprecated - Check @/utils/playback-profiles/index
 */

import {
	CodecType,
	ProfileConditionType,
	ProfileConditionValue
} from '@jellyfin/sdk/lib/generated-client';
import type { ProfileCondition, CodecProfile } from '@jellyfin/sdk/lib/generated-client';
import {
	isApple,
	isChromiumBased,
	isEdge,
	isMobile,
	isPs4,
	isTizen,
	isTv,
	isWebOS,
	isXbox,
	safariVersion
} from '../../../../utils/browser-detection';

/**
 * Gets the max video bitrate
 *
 * @returns Returns the MaxVideoBitrate
 */
function getGlobalMaxVideoBitrate(): number | undefined {
	let isTizenFhd = false;

	if (
		isTizen() &&
		'webapis' in window &&
		typeof window.webapis === 'object' &&
		window.webapis &&
		'productinfo' in window.webapis &&
		typeof window.webapis.productinfo === 'object' &&
		window.webapis.productinfo &&
		'isUdPanelSupported' in window.webapis.productinfo &&
		typeof window.webapis.productinfo.isUdPanelSupported === 'function'
	) {
		isTizenFhd = !window.webapis.productinfo.isUdPanelSupported();
	}

	// TODO: These values are taken directly from Jellyfin-web.
	// The source of them needs to be investigated.
	if (isPs4()) {
		return 8_000_000;
	}

	if (isXbox()) {
		return 12_000_000;
	}

	if (isTizen() && isTizenFhd) {
		return 20_000_000;
	}
}

/**
 * Creates a profile condition object for use in device playback profiles.
 *
 * @param Property - Value for the property
 * @param Condition - Condition that the property must comply with
 * @param Value - Value to check in the condition
 * @param IsRequired - Whether this property is required
 * @returns - Constructed ProfileCondition object
 */
function createProfileCondition(
	Property: ProfileConditionValue,
	Condition: ProfileConditionType,
	Value: string,
	IsRequired = false
): ProfileCondition {
	return {
		Condition,
		Property,
		Value,
		IsRequired
	};
}

/**
 * Gets the AAC audio codec profile conditions
 *
 * @param videoTestElement - A HTML video element for testing codecs
 * @returns - Array of ACC Profile conditions
 */
export function getAacCodecProfileConditions(
	videoTestElement: HTMLVideoElement
): ProfileCondition[] {
	const supportsSecondaryAudio = isTizen();

	const conditions: ProfileCondition[] = [];

	// Handle he-aac not supported
	if (
		!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')
	) {
		// TODO: This needs to become part of the stream url in order to prevent stream copy
		conditions.push(
			createProfileCondition(
				ProfileConditionValue.AudioProfile,
				ProfileConditionType.NotEquals,
				'HE-AAC'
			)
		);
	}

	if (!supportsSecondaryAudio) {
		conditions.push(
			createProfileCondition(
				ProfileConditionValue.IsSecondaryAudio,
				ProfileConditionType.Equals,
				'false'
			)
		);
	}

	return conditions;
}

/**
 * Gets an array with all the codec profiles that this client supports
 *
 * @param videoTestElement - A HTML video element for testing codecs
 * @returns - Array containing the different profiles for the client
 */
export function getCodecProfiles(videoTestElement: HTMLVideoElement): CodecProfile[] {
	const CodecProfiles: CodecProfile[] = [];

	const aacProfileConditions = getAacCodecProfileConditions(videoTestElement);

	const supportsSecondaryAudio = isTizen();

	if (aacProfileConditions.length > 0) {
		CodecProfiles.push({
			Type: CodecType.VideoAudio,
			Codec: 'aac',
			Conditions: aacProfileConditions
		});
	}

	if (!supportsSecondaryAudio) {
		CodecProfiles.push({
			Type: CodecType.VideoAudio,
			Conditions: [
				createProfileCondition(
					ProfileConditionValue.IsSecondaryAudio,
					ProfileConditionType.Equals,
					'false'
				)
			]
		});
	}

	let maxH264Level = 42;
	let h264Profiles = 'high|main|baseline|constrained baseline';

	if (isTv() || videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) {
		maxH264Level = 51;
	}

	if (videoTestElement.canPlayType('video/mp4; codecs="avc1.640834"').replace(/no/, '')) {
		maxH264Level = 52;
	}

	if (
		(isTizen() ||
			videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) && // TODO: These tests are passing in Safari, but playback is failing
		(!isApple() || !isWebOS() || !(isEdge() && !isChromiumBased()))
	) {
		h264Profiles += '|high 10';
	}

	let maxHevcLevel = 120;
	let hevcProfiles = 'main';
	const hevcProfilesMain10 = 'main|main 10';

	// HEVC Main profile, Level 4.1
	if (
		videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.4.L123"').replace(/no/, '') ||
		videoTestElement.canPlayType('video/mp4; codecs="hev1.1.4.L123"').replace(/no/, '')
	) {
		maxHevcLevel = 123;
	}

	// HEVC Main10 profile, Level 4.1
	if (
		videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L123"').replace(/no/, '') ||
		videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L123"').replace(/no/, '')
	) {
		maxHevcLevel = 123;
		hevcProfiles = hevcProfilesMain10;
	}

	// HEVC Main10 profile, Level 5.1
	if (
		videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L153"').replace(/no/, '') ||
		videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L153"').replace(/no/, '')
	) {
		maxHevcLevel = 153;
		hevcProfiles = hevcProfilesMain10;
	}

	// HEVC Main10 profile, Level 6.1
	if (
		videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '') ||
		videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L183"').replace(/no/, '')
	) {
		maxHevcLevel = 183;
		hevcProfiles = hevcProfilesMain10;
	}

	const hevcCodecProfileConditions: ProfileCondition[] = [
		createProfileCondition(
			ProfileConditionValue.IsAnamorphic,
			ProfileConditionType.NotEquals,
			'true'
		),
		createProfileCondition(
			ProfileConditionValue.VideoProfile,
			ProfileConditionType.EqualsAny,
			hevcProfiles
		),
		createProfileCondition(
			ProfileConditionValue.VideoLevel,
			ProfileConditionType.LessThanEqual,
			maxHevcLevel.toString()
		)
	];

	const h264CodecProfileConditions: ProfileCondition[] = [
		createProfileCondition(
			ProfileConditionValue.IsAnamorphic,
			ProfileConditionType.NotEquals,
			'true'
		),
		createProfileCondition(
			ProfileConditionValue.VideoProfile,
			ProfileConditionType.EqualsAny,
			h264Profiles
		),
		createProfileCondition(
			ProfileConditionValue.VideoLevel,
			ProfileConditionType.LessThanEqual,
			maxH264Level.toString()
		)
	];

	if (!isTv()) {
		h264CodecProfileConditions.push(
			createProfileCondition(
				ProfileConditionValue.IsInterlaced,
				ProfileConditionType.NotEquals,
				'true'
			)
		);
		hevcCodecProfileConditions.push(
			createProfileCondition(
				ProfileConditionValue.IsInterlaced,
				ProfileConditionType.NotEquals,
				'true'
			)
		);
	}

	const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString();

	if (globalMaxVideoBitrate) {
		h264CodecProfileConditions.push(
			createProfileCondition(
				ProfileConditionValue.VideoBitrate,
				ProfileConditionType.LessThanEqual,
				globalMaxVideoBitrate,
				true
			)
		);
	}

	if (globalMaxVideoBitrate) {
		hevcCodecProfileConditions.push(
			createProfileCondition(
				ProfileConditionValue.VideoBitrate,
				ProfileConditionType.LessThanEqual,
				globalMaxVideoBitrate,
				true
			)
		);
	}

	// On iOS 12.x, for TS container max h264 level is 4.2
	if (isApple() && isMobile() && Number(safariVersion()) < 13) {
		const codecProfile = {
			Type: CodecType.Video,
			Codec: 'h264',
			Container: 'ts',
			Conditions: h264CodecProfileConditions.filter((condition) => {
				return condition.Property !== 'VideoLevel';
			})
		};

		codecProfile.Conditions.push(
			createProfileCondition(
				ProfileConditionValue.VideoLevel,
				ProfileConditionType.LessThanEqual,
				'42'
			)
		);

		CodecProfiles.push(codecProfile);
	}

	CodecProfiles.push(
		{
			Type: CodecType.Video,
			Codec: 'h264',
			Conditions: h264CodecProfileConditions
		},
		{
			Type: CodecType.Video,
			Codec: 'hevc',
			Conditions: hevcCodecProfileConditions
		}
	);

	return CodecProfiles;
}
