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

ADOBE CONFIDENTIAL
------------------
Copyright 2021 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.

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

	-- WF.core.self_test
local WFTestFileUtils = require 'WFTestFileUtils'

	--WF.core.utils
local KSData = require 'KSData'
local KSIdGenerator = require 'KSIdGenerator'
local KSPathUtils = require 'KSPathUtils'
local KSTableUtils = require 'KSTableUtils'
local WFFileUtils = require 'WFFileUtils'
local WFPlatformInfo = require 'WFPlatformInfo'

	-- WF.oz_client.managed_catalog.sync
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'

	-- WF.oz_client.utils
local OzFilePaths

if WFPlatformInfo.isMobile() then
	OzFilePaths = require 'OzFilePaths'
end

local NmbLocalRenditionDigest

if WFPlatformInfo.isDesktop then
	NmbLocalRenditionDigest = require 'NmbLocalRenditionDigest'
end

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

--[[

	@mark WFCatVersionTestUtils
	
	WFCatVersionTestUtils is used for generating platform-specific Version documents
	for use in test cases.

]]--

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

local WFCatVersionTestUtils = {}

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

local deleteFile = function( path )
	if path then
		WFFileUtils.deleteFile( path )
	end
end

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

local tempFolderForTestName = {}

local function getDefaultLocalOnlySettings( rxTest, wfCatalog, assetId, optOverrides )

	local mockThumb = KSData.make( 'thumb_data' )

	local tempFolder = tempFolderForTestName[ rxTest:testName() ]
	
	if not tempFolder then
		tempFolder = WFTestFileUtils.createTestFolder( rxTest )
	end
	
	tempFolderForTestName[ rxTest:testName() ] = tempFolder

	-- Develop Settings

	local xmpDevelopSettingsFilePath, xmpDevelopSettingsRelPath,
		xmpDevelopSettingsFileSize, xmpDataAsStr, developSettingsSha256
			= WFCatAssetTestUtils.createXmpDevelopSettings( wfCatalog, assetId, tempFolder, optOverrides )
	
	-- Aux

	local auxLocalOnlySettings 
			= WFCatAssetTestUtils.getDefaultLocalOnlySettingsForImage_aux( rxTest, wfCatalog, optOverrides )
			
	-- Renditions
	
	local thumbnailFilePath = KSPathUtils.child( tempFolder, KSIdGenerator.uuidInLowercaseHex() )
	KSData.saveToFile( mockThumb, thumbnailFilePath )
	local thumbnailFileSize = WFFileUtils.fileAttributes( thumbnailFilePath ).fileSize
	local thumbnailData = tostring( mockThumb )
	local thumbnailContentId = KSIdGenerator.uuidInLowercaseHex()
	mockThumb:close()

	rxTest:finally( function()

		deleteFile( thumbnailFilePath )
		deleteFile( xmpDevelopSettingsFilePath )
		
	end )

	local localOnlySettings = {
	
		thumbnailFilePath = thumbnailFilePath,
		thumbnailFileSize = thumbnailFileSize,
		thumbnailData = thumbnailData,
		thumbnailContentId = thumbnailContentId,
		
		xmpDevelopSettingsFilePath = xmpDevelopSettingsFilePath,
		xmpDevelopSettingsRelPath = xmpDevelopSettingsRelPath,
		xmpDevelopSettingsFileSize = xmpDevelopSettingsFileSize,
		developSettingsSha256 = developSettingsSha256,
		xmpDevelopSettingsString = xmpDataAsStr,

	}

	return KSTableUtils.merge( {}, localOnlySettings, auxLocalOnlySettings )
end

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

local function getBaseDocValue( docId, optOverrides, localOnlySettings )

	local xmpCameraRaw = {
		sha256 = localOnlySettings.developSettingsSha256,
	}

	local expectedFormFactor
	
	if WFPlatformInfo.isMobile() then
		expectedFormFactor = 'phone'
	else
		expectedFormFactor = 'desktop'
	end

	local hasMasks = optOverrides.hasMasks
	local hasFilters = optOverrides.hasFilters
	local hasSourceOnlyFilters = optOverrides.hasSourceOnlyFilters

	local links = {
		[ '/rels/xmp_develop_create' ] = {
			href = '/v2/catalogs/{catalog_id}/assets/' .. docId .. '/revisions/{revision_id}/xmp/develop',
			templated = true
		}
	}

	if optOverrides.internalXmpCameraRaw then

		xmpCameraRaw = localOnlySettings.xmpDevelopSettingsString

	elseif not optOverrides.noDevelopSettingsLink then

		KSTableUtils.setNested(
				links, '/href/bogus/xmp_develop', '/rels/xmp/develop', 'href' )

		if optOverrides.ozDevelopSettingsAreInvalid then

			KSTableUtils.setNested(
					links, true, '/rels/xmp/develop', 'invalid' )

		end

	end
	
	if not optOverrides.noSufficientRenditionFoundOnOz then

		KSTableUtils.setNested( 
				links, '/href/bogus/thumbnail2x', '/rels/rendition_type/thumbnail2x', 'href' )

	end

	local revId = KSIdGenerator.uuidInLowercaseHex()

	local docValue = {
	
		_id = docId,
		type = 'version',
		_newRevId = revId,
		subtype = 'edit',
		name = KSIdGenerator.uuidInLowercaseHex(), -- Random Name
		asset = {
			id = KSIdGenerator.uuidInLowercaseHex()
		},
		develop = {
			processingModel = 'lightroom',
			croppedHeight = 1000,
			croppedWidth = 1000,
			xmpCameraRaw = xmpCameraRaw,
			userOrientation = 1,
			-- Masks
			masks = hasMasks and {
				[ localOnlySettings.mask1AuxId ] = {
					digest = localOnlySettings.mask1Fingerprint
				},
				[ localOnlySettings.mask2AuxId ] = {
					digest = localOnlySettings.mask2Fingerprint
				}
			} or nil,
			filters = ( hasFilters or hasSourceOnlyFilters ) and {
				[ localOnlySettings.filterGroupFingerprint ] = {
					[ localOnlySettings.filter1AuxId ] = {
						digest = localOnlySettings.filter1Fingerprint,
						sourceLongEdge = 6000
					},
					[ localOnlySettings.filter2AuxId ] = not hasSourceOnlyFilters and {
						digest = localOnlySettings.filter2Fingerprint,
						targeLongEdge = 2560
					} 
				}
			} or nil
		},
		importedOnDevice = {
			formFactor = expectedFormFactor
		},
		createdManually = false,
		_serverProvidedMetadata = {
			links = links,
			revision_ids = { revId }
		},
	}

	return docValue

end

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

local function createDesktopVersionDoc( rxTest, wfCatalog, docId, localOnlySettings, optOverrides )

	optOverrides = optOverrides or {}

	local docValue = getBaseDocValue( docId, optOverrides, localOnlySettings )

	docValue._localOnly = { 
	
		files = {

			xmp_develop = {
				path = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsRelPath or nil,
				fileSize = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsFileSize or nil,
				sha256 = localOnlySettings.developSettingsSha256,
			}
			
		}

	}
	
	if optOverrides.noLocalDevelopSettings and not optOverrides.internalXmpCameraRaw then
		docValue._localOnly.files.xmp_develop = nil
	end

	-- Add in rendition information. Need the fully formed doc value in order to do this.
	
	local renditionDigest = NmbLocalRenditionDigest.maybeComputeFromDocValue( docValue )

	if renditionDigest then
	
		local mockThumb = KSData.make( 'thumb_data' )
		
		local thumbnailFilePath = wfCatalog:fileSpec():pathForPreviewDigestAndLongEdge( 
				docValue._id, renditionDigest, 320, false )

		localOnlySettings.thumbnailFilePath = thumbnailFilePath

		local parentFolder = KSPathUtils.parent( thumbnailFilePath )
		WFFileUtils.mkdir( parentFolder )
		KSData.saveToFile( mockThumb, thumbnailFilePath )

		mockThumb:close()

		rxTest:finally( function()
		
			deleteFile( thumbnailFilePath )
		
		end )
	
	end

	return docValue

end

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

local function createiOSVersionDoc( rxTest, docId, localOnlySettings, optOverrides )

	optOverrides = optOverrides or {}

	local docValue = getBaseDocValue( docId, optOverrides, localOnlySettings )

	docValue._localOnly = { 
		
		files = {
		
			thumbnail2x = {
				path = localOnlySettings.thumbnailFilePath,
				contentId = localOnlySettings.thumbnailContentId,
				fileSize = localOnlySettings.thumbnailFileSize,
			},

			xmp_develop = {
				path = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsRelPath or nil,
				contentId = localOnlySettings.developSettingsSha256,
				fileSize = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsFileSize or nil,
			}
			
		}
		
	}

	if optOverrides.noLocalDevelopSettings and not optOverrides.internalXmpCameraRaw then
		docValue._localOnly.files.xmp_develop = nil
	end
	
	if optOverrides.noLocalThumbnail2x then
		docValue._localOnly.files.thumbnail2x = nil
	end

	return docValue

end

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

local function createAndroidVersionDoc( rxTest, docId, localOnlySettings, optOverrides )

	optOverrides = optOverrides or {}

	local thumbnail2xData = KSData.memoryMappedContentsOfFile( localOnlySettings.thumbnailFilePath )
	localOnlySettings.thumbMd5 = thumbnail2xData:digest( 'MD5' )
	thumbnail2xData:close()
	
	local revId = KSIdGenerator.uuidInLowercaseHex()

	local docValue = getBaseDocValue( docId, optOverrides, localOnlySettings )

	docValue._localOnly = { 
		
		thumbnail2x = {
			md5 = localOnlySettings.thumbMd5,
			referenceHeight = 960,
			referenceWidth = 1280,
			epoch = 1,
			revId = revId,
			size = localOnlySettings.thumbnailFileSize
		},
		
		files = {

			xmp_develop = {
				path = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsRelPath or nil,
				sha256 = localOnlySettings.developSettingsSha256,
				fileSize = not optOverrides.internalXmpCameraRaw and localOnlySettings.xmpDevelopSettingsFileSize or nil,
			}
			
		}
		
	}

	if optOverrides.noLocalDevelopSettings and not optOverrides.internalXmpCameraRaw then
		docValue._localOnly.files.xmp_develop = nil
	end
	
	if optOverrides.noLocalThumbnail2x then
		docValue._localOnly.thumbnail2x = nil
	end

	return docValue

end

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

--[[!
	\brief Creates a platform specific version document for use in tests.

	\param rxTest (rxTest)
	\param wfCatalog (WFCatalog)
	\param docId (optional string) optional document Id.
	\param optOverrides (optional table) Optional document modifiers:
	
		-- RENDITION OPTIONS
			
		noLocalThumbnail2x (boolean): If true, there were be no local thumbnail2x.
			
		noSufficientRenditionFoundOnOz (boolean): If true, there is no thumbnail
			link on Oz.

		-- DEVELOP OPTIONS
		
		internalXmpCameraRaw (boolean): If true, the dev settings are inlined and there
			are no external develop settings.
		
		noDevelopSettingsLink (boolean): If true, there will be no dev settings link on Oz.
		
		ozDevelopSettingsAreInvalid (boolean): If true, the settings on Oz will be marked as invalid.
		
		noLocalDevelopSettings (boolean): If true, there will be no local externalized dev settings.
		
		sharedDevelopSettings (boolean): If multiple assets are generated with 
			sharedDevelopSettings as true, the dev settings will match across the assets.
		
		hasDevelopAux (boolean): If true, the develop settings will include all kinds of
			develop aux

		noLocalDevelopAux (boolean): if true, all develop aux won't be on the local device.
		
		noLocalMasks (boolean): if true, the masks won't be on the local device.
		
		hasMasks (boolean): If true, the develop settings will reference two masks.
		
		sharedMasks (boolean): If multiple assets are generated with sharedMasks as true, the
			mask fingerprints will match across the assets.
		
		hasFilters (boolean): If true, the develop settings will reference one filter group with 
			two instances. Note: If true, then hasSourceOnlyFilters should be nil.

		hasSourceOnlyFilters (boolean): If true, the develop settings will reference one filter 
			group with only instance from source. Note: If true, then hasFilters should be nil.

		sharedFilters (boolean): If multiple assets are generated with sharedFilters as true, the
			filter group and fingerprints will match across the assets.

		noLocalFilters (boolean): if true, the filters won't be on the local device.
		
	\return (table) The Version document.
--]]

function WFCatVersionTestUtils.createVersionDocument( rxTest, wfCatalog, docId, optOverrides )

	docId = docId or KSIdGenerator.uuidInLowercaseHex()
	optOverrides = optOverrides or {}

	if optOverrides.hasDevelopAux then
		optOverrides.hasMasks = true
		optOverrides.hasFilters = true
	end

	if optOverrides.noLocalDevelopAux then
		optOverrides.noLocalMasks = true
		optOverrides.noLocalFilters = true
	end

	local docValue = {}

	local localOnlySettings = getDefaultLocalOnlySettings( rxTest, wfCatalog, docId, optOverrides )

	if WFPlatformInfo.isDesktop then
	
		docValue = createDesktopVersionDoc( rxTest, wfCatalog, docId, localOnlySettings, optOverrides )
	
	elseif WFPlatformInfo.isiOS then
	
		docValue = createiOSVersionDoc( rxTest, docId, localOnlySettings, optOverrides )
	
	elseif WFPlatformInfo.isAndroid then
	
		docValue = createAndroidVersionDoc( rxTest, docId, localOnlySettings, optOverrides )
	
	end

	-- add mask files

	if optOverrides.hasMasks then

		docValue._localOnly.files.aux = docValue._localOnly.files.aux or {}
		
		docValue._localOnly.files.aux[ localOnlySettings.mask1Fingerprint ] = {
			relativePath = localOnlySettings.mask1RelativeFilePath,
		}
		
		docValue._localOnly.files.aux[ localOnlySettings.mask2Fingerprint ] = {
			relativePath = localOnlySettings.mask2RelativeFilePath,
		}

	end

	-- add filter files

	if optOverrides.hasFilters or optOverrides.hasSourceOnlyFilters then

		docValue._localOnly.files.aux = docValue._localOnly.files.aux or {}

		docValue._localOnly.files.aux[ localOnlySettings.filter1Fingerprint ] = {
			relativePath = localOnlySettings.filter1RelativeFilePath,
		}

		if not optOverrides.hasSourceOnlyFilters then

			docValue._localOnly.files.aux[ localOnlySettings.filter2Fingerprint ] = {
				relativePath = localOnlySettings.filter2RelativeFilePath,
			}

		end

	end

	return docValue, localOnlySettings

end

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

return WFCatVersionTestUtils
