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

NmbStdProfileBinaryFetcherTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2018 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

------------------------------------------------------------------------------]]

if not require 'WFPlatformInfo'.hasACR then return {} end

--------------------------------------------------------------------------------
local WFRxRunUntilDone = require 'WFRxRunUntilDone'
local KSData = require 'KSData'
local KSIdGenerator = require 'KSIdGenerator'
local WFRxTestCase = require 'WFRxTestCase'
local NmbStdProfileBinaryFetcher = require 'NmbStdProfileBinaryFetcher'
local WFCatSpecMock = require 'WFCatSpecMock'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFMockHttpRequest = require 'WFMockHttpRequest'

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

local kUserId = '87f526b44f9e41eca6cb5a550f84ceb6'
	-- Helpful bash one-liner. Put a new uuid on the clipboard (mac cmdline):
	-- uuidgen	| perl -p -e 's/-//g;s/[A-Z]/lc($&)/ge;' | pbcopy

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

local NmbStdProfileBinaryFetcherTest = {}

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

local function pack( ... )

	return { ... }

end

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

--local function addToArray( array, v )
--
--	array[ #array + 1 ] = v
--
--	return array
--
--end
--------------------------------------------------------------------------------

local function addStdCameraProfileAssets( rxTest, profileCatalog, fileNames )

	local docValues = {}
	
	for i, fileName in ipairs( fileNames ) do
		docValues[ i ] = {
	
			_id = KSIdGenerator.uuidInLowercaseHex(),
			type = "asset",
			subtype = "camera_profile",
			name = "dummy name",
			resolvedDigest = "dummy digest",
			importSource = {
				sha256 = "dummy sha",
			},
			fileName = fileName,
			model = "Dummy Camera",
			cameraProfileDigest = "Dummy profile digest",
			_serverProvidedMetadata = {
				links = {
					[ '/rels/master' ] = {
						href = "path_to_master"
					}
				}
			}
		}
	end
	
	
	rxTest:expectSingleValue(

		profileCatalog:docStore():bulkSetDocValue( docValues ),

		':ignore:' )
end

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

local function getFileNamesForCameraModel( rxTest, cameraModel )
	
	local fileNames = {}
	
	rxTest:expectSingleValue(
		
		require "NmbAcr".WFAcrOperations.getCoreCameraProfilesMap()
			:tap( function( modelProfileMap )
				local profileInfos = modelProfileMap[ string.upper( cameraModel ) ]
				for i, profileInfo in pairs( profileInfos ) do
					fileNames[ i ] = profileInfo.fileName
				end
			end ),
			
		':ignore:' )
	
	return fileNames
end

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

local function addAssetWithCameraModel( rxTest, catalog, cameraModel )

	local id = KSIdGenerator.uuidInLowercaseHex()
	local docValue = {
	
		_id = id,
		type = "asset",
		subtype = "image",
		xmp = {
			tiff = {
				Model = cameraModel,
			}
		},
	}
	
	rxTest:expectSingleValue(

		catalog:docStore():setDocValue( docValue ),

		':ignore:' )
end

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

local function addSuccessResponses( rxTest, catalogSpec, count )
	
	local response = WFMockHttpRequest()
	response:withResponseHeaders( {
		[ "Content-Length" ] = 13
	})
	
	for i = 1, count do
		local data = KSData.make( "pseudo-master" )
		
		catalogSpec:expectHttpRequest(
			response
				:get( "path_to_master" )
				:respond( '200', data ) )
	end
	
end

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

local function expectDataOfType( responseStream, count, data )

	for i = 1, count do
		responseStream:expectData( data )
	end
	
end

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

function NmbStdProfileBinaryFetcherTest.rxTestFetchProfilesForOneCameraModel( rxTest )
	rxTest:setTimeLimit( 10 )
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', kUserId, rxTest )
	
	local profileCatSpec = WFCatSpecMock( 'f270b1c513494be08836d593cd1d6363', kUserId, rxTest )

	local cameraModel = "Nikon D5200"
	local fileNames = getFileNamesForCameraModel( rxTest, cameraModel )
	addSuccessResponses( rxTest, catalogSpec, #fileNames )
	
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec, 'NmbCatalog' )
	local profileCatalog = WFCatMockCatalog.createWFCatalogForProfiles( 
		rxTest, profileCatSpec, 'NmbProfilesIndexDefinitions.lua', 'NmbProfileCatalog' )

	local fetcher = NmbStdProfileBinaryFetcher( catalog, profileCatalog )
	
	
	addStdCameraProfileAssets( rxTest, profileCatalog, fileNames )
	
	local responseStream = rxTest:observe( 
		fetcher:getResponseStream():map( pack )
			:map( function( result ) 
				return { result[ 1 ] }
			end ))
	fetcher:start()
	
	addAssetWithCameraModel( rxTest, catalog, cameraModel )
	expectDataOfType( responseStream, #fileNames, { true } )
	
	fetcher:stop()
	fetcher:close()

end

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

function NmbStdProfileBinaryFetcherTest.rxTestFetchProfilesForMultipleCameraModel( rxTest )
	rxTest:setTimeLimit( 10 )
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', kUserId, rxTest )
	
	local profileCatSpec = WFCatSpecMock( 'f270b1c513494be08836d593cd1d6363', kUserId, rxTest )

	local cameraModel1 = "Nikon D5200"
	local cameraModel2 = "Canon EOS 70D"
	local fileNames = getFileNamesForCameraModel( rxTest, cameraModel1 )
	local fileNames2 = getFileNamesForCameraModel( rxTest, cameraModel2 )
	addSuccessResponses( rxTest, catalogSpec, #fileNames + #fileNames2 )
	
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec, 'NmbCatalog' )
	local profileCatalog = WFCatMockCatalog.createWFCatalogForProfiles( 
		rxTest, profileCatSpec, 'NmbProfilesIndexDefinitions.lua', 'NmbProfileCatalog' )

	local fetcher = NmbStdProfileBinaryFetcher( catalog, profileCatalog )
	
	
	addStdCameraProfileAssets( rxTest, profileCatalog, fileNames )
	addStdCameraProfileAssets( rxTest, profileCatalog, fileNames2 )
	
	local responseStream = rxTest:observe( 
		fetcher:getResponseStream():map( pack )
			:map( function( result ) 
				return { result[ 1 ] }
			end ))
	fetcher:start()
	
	addAssetWithCameraModel( rxTest, catalog, cameraModel1 )
	addAssetWithCameraModel( rxTest, catalog, cameraModel2 )
	expectDataOfType( responseStream, #fileNames + #fileNames2, { true } )
	
	
	fetcher:stop()
	fetcher:close()

end

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

function NmbStdProfileBinaryFetcherTest.rxTestProcessCameraModel( rxTest )
	rxTest:setTimeLimit( 10 )
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', kUserId, rxTest )
	
	local profileCatSpec = WFCatSpecMock( 'f270b1c513494be08836d593cd1d6363', kUserId, rxTest )

	local cameraModel = "Nikon D5200"
	local fileNames = getFileNamesForCameraModel( rxTest, cameraModel )
	addSuccessResponses( rxTest, catalogSpec, #fileNames )
	
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec, 'NmbCatalog' )
	local profileCatalog = WFCatMockCatalog.createWFCatalogForProfiles( 
		rxTest, profileCatSpec, 'NmbProfilesIndexDefinitions.lua', 'NmbProfileCatalog' )
	addStdCameraProfileAssets( rxTest, profileCatalog, fileNames )

	local fetcher = NmbStdProfileBinaryFetcher( catalog, profileCatalog )
	
	local responseStream = rxTest:observe( 
		fetcher:getResponseStream():map( pack )
			:map( function( result ) 
				return { result[ 1 ] }
			end ))
	fetcher:start()
	
	-- Do not add the image assets. Directly call
	-- the process function
	fetcher:makeAdjustablePriorityASAPRequestForCameraModel( cameraModel )
		:call( WFRxRunUntilDone )
	
	addAssetWithCameraModel( rxTest, catalog, cameraModel )
	expectDataOfType( responseStream, #fileNames, { true } )
	
	fetcher:stop()
	fetcher:close()

end

--------------------------------------------------------------------------------
--[[ pclarke 2020-06-04: removed out at @matthewj's direction due to spurious failures

function NmbStdProfileBinaryFetcherTest.rxTestEnsureStandardProfileExists( rxTest )
	rxTest:setTimeLimit( 10 )
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', kUserId, rxTest )
	local profileCatSpec = WFCatSpecMock( 'f270b1c513494be08836d593cd1d6363', kUserId, rxTest )
	addErrorResponses( rxTest, catalogSpec, 1 )
	addSuccessResponses( rxTest, catalogSpec, 1 )
	
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec, 'NmbCatalog' )
	local profileCatalog = WFCatMockCatalog.createWFCatalogForProfiles( 
		rxTest, profileCatSpec, 'NmbProfilesIndexDefinitions.lua', 'NmbProfileCatalog' )
	
	addStdCameraProfileAssets( rxTest, profileCatalog, { "Nikon D5200 Adobe Standard.dcp" } )

	local fetcher = NmbStdProfileBinaryFetcher( catalog, profileCatalog )
	
	
	local responseStream = rxTest:observe( 
		fetcher:getResponseStream():map( pack )
			:map( function( result ) 
				return { result[ 1 ] }
			end ))
	
	
	-- Bogus href. Should return false.
	local outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "bogus_url" ) )
	outputStream:expectDataWithinTime( 4, false )
	
	
	-- Bogus href. Should return false.
	outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "bogus_url" ) )
	outputStream:expectDataWithinTime( 4, false )
	
	
	-- Not started. Should return false.
	outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "path_to_master" ) )
	outputStream:expectDataWithinTime( 4, false )
	
	fetcher:start()
	
	-- Valid url. But download failed. Should return false
	outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "path_to_master" ) )
	outputStream:expectDataWithinTime( 4, false )
	
	-- The response stream too should get the update
	-- in case we downloaded a profile
	expectDataOfType( responseStream, 2, { false } )
	
	-- Valid url. Should download and return true.
	outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "path_to_master" ) )
	outputStream:expectDataWithinTime( 4, true )
	
	-- The response stream too should get the update
	-- in case we downloaded a profile
	expectDataOfType( responseStream, 2, { true } )
	
	-- Valid url. File already present. Should return true
	outputStream = rxTest:observe( fetcher:ensureStandardCameraProfileExists( "path_to_master" ) )
	outputStream:expectDataWithinTime( 2, true )
	
	fetcher:stop()
	fetcher:close()

end
--]]

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

function NmbStdProfileBinaryFetcherTest.rxTestMakeAdjustablePriorityASAPRequestForCameraModel( rxTest )
	rxTest:setTimeLimit( 10 )
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', kUserId, rxTest )
	
	local profileCatSpec = WFCatSpecMock( 'f270b1c513494be08836d593cd1d6363', kUserId, rxTest )

	local cameraModel = "Nikon D5200"
	local fileNames = getFileNamesForCameraModel( rxTest, cameraModel )
	addSuccessResponses( rxTest, catalogSpec, #fileNames )
	
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec, 'NmbCatalog' )
	local profileCatalog = WFCatMockCatalog.createWFCatalogForProfiles( 
		rxTest, profileCatSpec, 'NmbProfilesIndexDefinitions.lua', 'NmbProfileCatalog' )
	addStdCameraProfileAssets( rxTest, profileCatalog, fileNames )

	local fetcher = NmbStdProfileBinaryFetcher( catalog, profileCatalog )


	-- Not started. Should return nil.
	local outputStream = rxTest:observe( fetcher:makeAdjustablePriorityASAPRequestForCameraModel( cameraModel ))
	outputStream:expectData()
	
	local refreshStreamCount = 0
	
	local refreshStreamObserver = rxTest:observe( fetcher:getRefreshStream()
		:map( pack )
		:map( function( result )
			refreshStreamCount = refreshStreamCount + 1
			return refreshStreamCount
		end ))
	
	fetcher:start()
	
	-- Should return cancel function
	local cancelFn
	rxTest:expectSingleValue(

		fetcher:makeAdjustablePriorityASAPRequestForCameraModel( cameraModel )
			:tap( function( fn )
				cancelFn = fn
			end ),

		':ignore:' )
		
	rxTest:expectEqual( type( cancelFn ) , "function" )
	refreshStreamObserver:expectDataWithinTime( 10, #fileNames )
	
	-- TODO [ashj 2018-09-20]: Need to validate also
	cancelFn()
	
	fetcher:stop()
	fetcher:close()

end

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

-- FIXME [jandrew 3/27/2018]: This test suite fails on Android.
local WFPlatformInfo = require 'WFPlatformInfo'

if WFPlatformInfo.isAndroid then
	return {}
else
	return WFRxTestCase.wrapSuite( 'NmbStdProfileBinaryFetcherTest', NmbStdProfileBinaryFetcherTest )
end
