--[[----------------------------------------------------------------------------

PixelProviderPendingDownloadInfoCacheTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2024 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.
------------------------------------------------------------------------------]]

	-- Rx
local Rx = require 'Rx'

	-- wf.core
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFRxTestCase = require 'WFRxTestCase'
local KSTableUtils = require 'KSTableUtils'
local WFFunctionUtils = require 'WFFunctionUtils'

--------------------------------------------------------------------------------

local WFPlatformInfo = require 'WFPlatformInfo'
if not WFPlatformInfo.isDesktop then
	return {}
end

--------------------------------------------------------------------------------

local PixelProviderSharedBlobCache = require 'PixelProviderSharedBlobCache'
local PixelPathProviderScheduler = require 'PixelPathProviderScheduler'
local PixelPathProviderRequestTypes = require 'PixelPathProviderRequestTypes'
local PixelProviderPendingDownloadInfoCache = 
		require 'PixelProviderPendingDownloadInfoCache'

--------------------------------------------------------------------------------

local function makeSchedulerForTest( rxTest )

	local catalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local scheduler = PixelPathProviderScheduler( catalog )

	rxTest:finally( function() scheduler:close() end )

	return scheduler, catalog

end

--------------------------------------------------------------------------------

local function pixStreamId( i )

	return string.format( "pixStreamId%s", i )

end

--------------------------------------------------------------------------------

local function localAssetId( i )

	return i

end


--==============================================================================
-- rxTestGetNeedsDownloadAPI
--==============================================================================

local function rxTestGetNeedsDownloadAPI( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	-- request 1 is highest priority
	scheduler:addRequest( pixStreamId( 1 ), localAssetId( 1 ),
							PixelPathProviderRequestTypes.names.highest, 1 )

	-- request 2 is not highest or lowest priority
	scheduler:addRequest( pixStreamId( 2 ), localAssetId( 2 ),
							PixelPathProviderRequestTypes.names.grid_visible, 2 )

	local needsDownloadStates = PixelProviderSharedBlobCache.needsDownloadStates

	local needsProxyDownloadToFileStates =
			KSTableUtils.mapArrayToSet( 
				scheduler:_getSourceStatesForTransition( 'start_proxy_download_to_file' ) )

	local needsOriginalDownloadToFileStates =
			KSTableUtils.mapArrayToSet( 
				scheduler:_getSourceStatesForTransition( 'start_original_download_to_file' ) )

	local needsDownloadToFileStates =
			PixelProviderSharedBlobCache.appendT( 
				KSTableUtils.extractKeys( needsProxyDownloadToFileStates ),
				KSTableUtils.extractKeys( needsOriginalDownloadToFileStates ) )

	-- we now have two requests, we will set one state to download to file and
	-- the other to download to memory.

	for _, needsDownloadState in ipairs( needsDownloadStates ) do

		for _, needsDownloadToFileState in ipairs( needsDownloadToFileStates ) do

			rxTest:logf( "Testing with two states: %s and %s",
							needsDownloadToFileState, needsDownloadState )

			for _, higherPriorityDownloadToFile in ipairs( { true, false } ) do

				local pendingDownloadInfoCache = 
						PixelProviderPendingDownloadInfoCache( 2 )

				local higherPriorityState = 
						higherPriorityDownloadToFile and
							needsDownloadToFileState or needsDownloadState

				SchedulerTestAPI.setState( 
					scheduler, pixStreamId( 1 ), localAssetId( 1 ),
					higherPriorityState )

				local lowerPriorityState =
						higherPriorityState ~= needsDownloadToFileState and
							needsDownloadToFileState or needsDownloadState

				SchedulerTestAPI.setState( 
					scheduler, pixStreamId( 2 ), localAssetId( 2 ),
					lowerPriorityState )

				local higherPriorityPopFunction =
						higherPriorityDownloadToFile and
							pendingDownloadInfoCache.getNextDownloadToFileRequest or
							pendingDownloadInfoCache.getNextDownloadToBlobRequest

				local lowerPriorityPopFunction =
						not higherPriorityDownloadToFile and
							pendingDownloadInfoCache.getNextDownloadToFileRequest or
							pendingDownloadInfoCache.getNextDownloadToBlobRequest

				rxTest:expectEqual( nil, 
					lowerPriorityPopFunction( pendingDownloadInfoCache, scheduler ) )

				local higherPriorityRequest =
						higherPriorityPopFunction( pendingDownloadInfoCache, scheduler )

				rxTest:expectEqual( true, higherPriorityRequest ~= nil )

				-- act as if we started the higher priority request
				local higherPriorityRequestTransition =
						higherPriorityDownloadToFile and
							( 
								( needsProxyDownloadToFileStates[ needsDownloadToFileState ] and
									'start_proxy_download_to_file' ) or
								( needsOriginalDownloadToFileStates[ needsDownloadToFileState ] and
									'start_original_download_to_file' ) or
								'bogus_download_to_file_state' ) or
							'start_download'

				scheduler
					:_applyTransitionToRequest( 
						higherPriorityRequest, higherPriorityRequestTransition )

				local lowerPriorityRequest =
						lowerPriorityPopFunction( pendingDownloadInfoCache, scheduler )

				rxTest:expectEqual( true, lowerPriorityRequest ~= nil )

				local lowerPriorityRequestTransition =
						not higherPriorityDownloadToFile and
							( 
								( needsProxyDownloadToFileStates[ needsDownloadToFileState ] and
									'start_proxy_download_to_file' ) or
								( needsOriginalDownloadToFileStates[ needsDownloadToFileState ] and
									'start_original_download_to_file' ) or
								'bogus_download_to_file_state' ) or
							'start_download'

				scheduler
					:_applyTransitionToRequest( 
						lowerPriorityRequest, lowerPriorityRequestTransition )

				rxTest:expectEqual( nil, 
					higherPriorityPopFunction( pendingDownloadInfoCache, scheduler ) )

				rxTest:expectEqual( nil, 
					lowerPriorityPopFunction( pendingDownloadInfoCache, scheduler ) )

			end

		end

	end

end

--==============================================================================
-- start download to file test functions
--==============================================================================

local function makeProxyRenderInfo( proxySize )

	return { proxies = { { size = proxySize, href = "yass" } } }

end

--------------------------------------------------------------------------------

local _hasOrigBaseRenderInfo = { ozValidOriginalLink = "yep" }

--------------------------------------------------------------------------------

local _proxySizes = {
	'2560',
	'1080p',
	'1080p709',
	'720p',
	'360p'
}

--------------------------------------------------------------------------------

local _downloadToFileTypePairs =
	WFFunctionUtils.map( 
		function( proxySize )
			return { 'proxy', proxySize } 
		end,
		_proxySizes )

--------------------------------------------------------------------------------

_downloadToFileTypePairs[ #_downloadToFileTypePairs + 1 ] = { 'original', 'master' }

--------------------------------------------------------------------------------
-- _downloadToFileTypePairs is
--
-- {
-- 	{ 'proxy', '2560' },
-- 		...
-- 	{ 'proxy', '360p' },
-- 	{ 'original', 'master' }
-- }

--==============================================================================
-- rxTestStartNewDownloadToFileNoBaseRenderInfo
--==============================================================================

local function rxTestStartNewDownloadToFileNoBaseRenderInfo( rxTest )

	WFFunctionUtils.map( 
		function( downloadToFileTypePair )

			local pendingDownloadInfoCache = 
					PixelProviderPendingDownloadInfoCache( 2 )

			local ozBinaryType, ozBinarySubtype = unpack( downloadToFileTypePair )

			rxTest:logf( "Testing missing render info for %s %s",
							ozBinaryType, ozBinarySubtype )

			local canonicalLocalPathStream = Rx.Observable.never()

			local downloadToFileFunc = function() end

			local baseRenderInfoCache = 
				{ peekCacheItem = function() return {} end }

			rxTest:expectEqual( 
				true,
				not pendingDownloadInfoCache
					:startNewDownloadToFile( 
						downloadToFileFunc, canonicalLocalPathStream,
						baseRenderInfoCache, 1, "ozAssetId", ozBinaryType,
						ozBinarySubtype, 1 ) )

		end,
		_downloadToFileTypePairs )

end

--==============================================================================
-- rxTestStartNewDownloadToFileCancel
--==============================================================================

local function rxTestStartNewDownloadToFileCancel( rxTest )

	WFFunctionUtils.map( 
		function( downloadToFileTypePair )

			for _, earlyCancel in ipairs( { true, false } ) do

				local ozAssetId = "ozAssetId"

				local pendingDownloadInfoCache = 
						PixelProviderPendingDownloadInfoCache( 2 )

				local ozBinaryType, ozBinarySubtype = unpack( downloadToFileTypePair )

				rxTest:logf( "Testing %s cancel before start download for %s %s",
								earlyCancel and "early" or "in flight",
								ozBinaryType, ozBinarySubtype )
				
				local canonicalLocalPathStream = 
						earlyCancel and
							Rx.Observable.never() or
							Rx.Observable.just( "fakePath" )

				local didRequestBinaryAtUrlToFile = false

				local function downloadToFileFunc() 

					didRequestBinaryAtUrlToFile = true

				end

				local baseRenderInfoCache = 
					{ 
						peekCacheItem = 
							function() 

								return ozBinaryType == 'proxy' and
									makeProxyRenderInfo( ozBinarySubtype ) or
									_hasOrigBaseRenderInfo

							end }

				local didStart = 
					pendingDownloadInfoCache
						:startNewDownloadToFile( 
							downloadToFileFunc, canonicalLocalPathStream,
							baseRenderInfoCache, 1, "ozAssetId", ozBinaryType,
							ozBinarySubtype, 1 )

				rxTest:expectEqual( true, didStart )

				rxTest:expectEqual( not earlyCancel, didRequestBinaryAtUrlToFile )

				pendingDownloadInfoCache
					:cancelAndRemoveDownload( 
						"earlyCancel", ozAssetId, ozBinaryType, ozBinarySubtype )

			end

		end,
		_downloadToFileTypePairs )

end

--==============================================================================
-- rxTestStartNewDownloadToFileDestPathError
--==============================================================================

local function rxTestStartNewDownloadToFileDestPathError( rxTest )

	WFFunctionUtils.map( 
		function( downloadToFileTypePair )

			for _, haveError in ipairs( { true, false } ) do

				local ozAssetId = "ozAssetId"

				local pendingDownloadInfoCache = 
						PixelProviderPendingDownloadInfoCache( 2 )

				local destPathFailed = false

				local destPathFailedSubscription = 
					pendingDownloadInfoCache
						:downloadToFileDestPathErrorStream()
						:subscribe( 
							function() 

								destPathFailed = true

							end )

				local ozBinaryType, ozBinarySubtype = unpack( downloadToFileTypePair )

				rxTest:logf( "Testing dest path fail subscription with%s failure before start download for %s %s",
								haveError and "" or "out",
								ozBinaryType, ozBinarySubtype )
				
				local canonicalLocalPathStream = 
						haveError and
							Rx.Observable.throw( "FAIL" ) or
							Rx.Observable.just( "fakePath" )

				local didRequestBinaryAtUrlToFile = false

				local function downloadToFileFunc() 

					didRequestBinaryAtUrlToFile = true

				end

				local baseRenderInfoCache = 
					{ 
						peekCacheItem = 
							function() 

								return ozBinaryType == 'proxy' and
									makeProxyRenderInfo( ozBinarySubtype ) or
									_hasOrigBaseRenderInfo

							end }

				local didStart = 
					pendingDownloadInfoCache
						:startNewDownloadToFile( 
							downloadToFileFunc, canonicalLocalPathStream,
							baseRenderInfoCache, 1, "ozAssetId", ozBinaryType,
							ozBinarySubtype, 1 )

				rxTest:expectEqual( true, didStart )

				rxTest:expectEqual( not haveError, didRequestBinaryAtUrlToFile )

				rxTest:expectEqual( haveError, destPathFailed )

				pendingDownloadInfoCache
					:cancelAndRemoveDownload( 
						"earlyCancel", ozAssetId, ozBinaryType, ozBinarySubtype )

				destPathFailedSubscription:dispose()

			end

		end,
		_downloadToFileTypePairs )

end

--==============================================================================

return WFRxTestCase.wrapSuite( 'PixelProviderPendingDownloadInfoCacheTest', {

	rxTestGetNeedsDownloadAPI = rxTestGetNeedsDownloadAPI,

	rxTestStartNewDownloadToFileNoBaseRenderInfo = 
		rxTestStartNewDownloadToFileNoBaseRenderInfo,

	rxTestStartNewDownloadToFileCancel = 
		rxTestStartNewDownloadToFileCancel,

	rxTestStartNewDownloadToFileDestPathError = 
		rxTestStartNewDownloadToFileDestPathError

} )
