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

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

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

local Rx = require 'Rx'

	-- WF.core.os
local WFPlatformInfo = require 'WFPlatformInfo'

	-- WF.core.rxlua
local WFRxTestCase = require 'WFRxTestCase'

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

	-- WF.core.lua
local KSData = require 'KSData'

local LrmCatalogTestHelper = require "LrmCatalogTestHelper"

local WFOzRenditionServerUtils = require 'WFOzRenditionServerUtils'

local LrmOzDevelopSession = require "LrmOzDevelopSession"

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

-- SPAM [ashj 2020-04-27]: LrmOzDevelopSessionTest uses RenditionServer
-- functions which are used only in Android as of now.
if not WFPlatformInfo.isAndroid then return {} end

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

local LrmOzDevelopSessionTest = {}

local catalog, catalogId

local TEST_TIMEOUT = 5

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

local function generateAsset( rxTest, catalog )
	local assetId = KSIdGenerator.uuidInLowercaseHex()

	local overlay = {
		type = 'asset',
		subtype = 'image',
		_id = assetId,
		importSource = {
			originalWidth = 100,
			originalHeight = 100,
		},
		_serverProvidedMetadata = {
			links = {
				[ '/rels/master' ] = assetId,
			}
		}
	}
	
	rxTest:expectSingleValue( catalog:docStore():applyOverlay( overlay ),
		':ignore:' )
	
	return assetId

end

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

local function updateDevelopSection( rxTest, catalog, assetId, developSection )
	local overlay = {
		_id = assetId,
		type = 'asset',
		subtype = 'image',
		
		develop = developSection
	}
	
	local revId
	rxTest:expectSingleValue( catalog:docStore():applyOverlay( overlay )
		:tap( function( newRevId )
			revId = newRevId
		end ),
		':ignore:' )

	return revId
end

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

local function getMD5( assetId, ksdata )
	local newMD5 = ksdata:digest( 'MD5' )
	return WFOzRenditionServerUtils.getFullMD5HashedKey( newMD5, assetId )
end

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

local function stripEpoch( t )
	if t then
		t.epoch = nil
	end
end

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

function LrmOzDevelopSessionTest.setUp()
	
	local _
	catalog, _, catalogId = LrmCatalogTestHelper.makeCatalogService()
	
end

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

function LrmOzDevelopSessionTest.tearDown()
	
	if catalog then
	
		catalog:close()
		catalog = nil
	
	end
	
end

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

function LrmOzDevelopSessionTest.rxTestUpdateRenditionsForDevSettings( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )
	
	local photoId = generateAsset( rxTest, catalog )
	local developSession = LrmOzDevelopSession( catalog, photoId )
	local thumbData = KSData.make( "thumbKSData" )
	local previewData = KSData.make( "prevKSData" )
	local croppedWidth = 100
	local croppedHeight = 200
	
	-- Develop settings doesn't match
	
	rxTest:expectSingleValue( 
		developSession:updateRenditionsForDevSettings({
			thumbnail = thumbData,
			preview = previewData,
			xmpCameraRaw = "<xmp></xmp>",
			userOrientation = 1,
			croppedWidth = croppedWidth,
			croppedHeight = croppedHeight,
		}),
		false )
		
	
	-- Positive case
		
	local newRevId = updateDevelopSection( rxTest, catalog, photoId, {
		userUpdated = "2020-03-09T08:01:16.540Z",
		croppedWidth = croppedWidth,
		croppedHeight = croppedHeight,
		processingModel = "lightroom",
		userOrientation = 1,
		xmpCameraRaw = "<xmp/>"
	})
	
	rxTest:expectSingleValue( 
		developSession:updateRenditionsForDevSettings({
			thumbnail = KSData.make( "thumbKSData" ),
			preview = KSData.make( "prevKSData" ),
			xmpCameraRaw = "<xmp/>",
			userOrientation = 1,
			croppedWidth = croppedWidth,
			croppedHeight = croppedHeight,
		}),
		':ignore:' )
		
	
	local expectedTable = {
		thumbnail2x = {
			revId = newRevId,
			size = KSData.length( thumbData ),
			referenceWidth = croppedWidth,
			referenceHeight = croppedHeight,
			md5 = getMD5( photoId, thumbData )
		},
		preview = {
			revId = newRevId,
			size = KSData.length( previewData ),
			referenceWidth = croppedWidth,
			referenceHeight = croppedHeight,
			md5 = getMD5( photoId, previewData )
		},
	}
	
	local result = {}
	
	rxTest:expectSingleValue( 
		catalog:docStore():docValue( photoId )
			:tap( function( docValue )
				-- Take only relevant fields
				
				local thumbTable = docValue._localOnly[ 'thumbnail2x' ]
				stripEpoch( thumbTable )
				
				local previewTable = docValue._localOnly[ 'preview' ]
				stripEpoch( previewTable )
				
				result = {
					thumbnail2x = thumbTable,
					preview = previewTable,
				}
			end ),
		':ignore:' )
	
	rxTest:expectEqual( expectedTable, result )
	
end

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

function LrmOzDevelopSessionTest.rxTestSaveAndCloseDeleteOldExternalSettings( rxTest )
	rxTest:setTimeLimit( 10 )
	local OzFilePaths = require 'OzFilePaths'
	
	local photoId = generateAsset( rxTest, catalog )
	
	local fakeThumbnail = KSData.make( 'fakeThumbnailData' )
	local fakeHighDpiThumbnail = KSData.make( 'fakeHighDpiThumbnailData' )
	
	local saveSettingsChanges = function( developSession, changes )
		return Rx.Observable.create(
			function( observer )
			
				developSession:saveAndCloseP( changes )
					:whenResolvedDo( function( status, result )
						if status == 'data' then
							observer:onNext( true )
							observer:onCompleted()
						else
							observer:onCompleted()
						end
					end )
					:runUntilDone()
			end )
		end
		
	local xmpDevelopPathObserver = rxTest:observe( catalog:docStore():ongoingDocValue( photoId )
			:map( function( docValue )
				return KSTableUtils.derefOpt( docValue, '_localOnly', 'files', 'xmp_develop', 'path' )
			end ) )
	
	local developSession = LrmOzDevelopSession( catalog, photoId )
	local externalSettingsXmp = KSData.make( '<xmp/>' )
	local externalSettingsXmpSha256 = externalSettingsXmp:digest( 'SHA256' )
	local externalSettingsRelPath, externalSettingsAbsPath = OzFilePaths.getXmpDevelopPath( catalogId, { _id = photoId }, externalSettingsXmpSha256, true )
	KSData.saveToFile( externalSettingsXmp, externalSettingsAbsPath )
	
	local changes = {
		appliedCameraProfileDigest = "54650a341b5b5ccae8442d0b43a92bce",
		cameraModelName = "JPEG",
		cameraProfileFileName = "JPEG Embedded.dcp",
		cameraProfileLink = "",
		croppedHeight = 960,
		croppedWidth = 1280,
		crsVersion = "12.3",
		fromDefaults = false,
		localXmpDevelopPath = externalSettingsRelPath,
		userOrientation = 8,
		thumbnail = fakeThumbnail,
		highDpiThumbnail = fakeHighDpiThumbnail,
		xmpCameraRaw = {
			sha256 = externalSettingsXmpSha256,
		},
	}
	rxTest:expectSingleValue( saveSettingsChanges( developSession, changes ), true )
	
	xmpDevelopPathObserver:expectDataWithinTime( 3, externalSettingsRelPath )
	
	rxTest:expectEqual( true, not not WFFileUtils.exists( externalSettingsAbsPath ) )
	
	developSession = LrmOzDevelopSession( catalog, photoId )
	
	local externalSettingsXmp2 = KSData.make( '<xmp          />' )
	local externalSettingsXmpSha2562 = externalSettingsXmp2:digest( 'SHA256' )
	local externalSettingsRelPath2, externalSettingsAbsPath2 = OzFilePaths.getXmpDevelopPath( catalogId, { _id = photoId }, externalSettingsXmpSha2562, true )
	KSData.saveToFile( externalSettingsXmp2, externalSettingsAbsPath2 )
	
	rxTest:finally( function()
		WFFileUtils.delete( externalSettingsAbsPath )
		WFFileUtils.delete( externalSettingsAbsPath2 )
	end )
	
	local changes2 = {
		appliedCameraProfileDigest = "54650a341b5b5ccae8442d0b43a92bce",
		cameraModelName = "JPEG",
		cameraProfileFileName = "JPEG Embedded.dcp",
		cameraProfileLink = "",
		croppedHeight = 960,
		croppedWidth = 1280,
		crsVersion = "12.3",
		fromDefaults = false,
		localXmpDevelopPath = externalSettingsRelPath2,
		userOrientation = 8,
		thumbnail = fakeThumbnail,
		highDpiThumbnail = fakeHighDpiThumbnail,
		xmpCameraRaw = {
			sha256 = externalSettingsXmpSha2562,
		},
	}
	rxTest:expectSingleValue( saveSettingsChanges( developSession, changes2 ), true )
	
	xmpDevelopPathObserver:expectDataWithinTime( 3, externalSettingsRelPath2 )
	
	rxTest:expectEqual( true, not not WFFileUtils.exists( externalSettingsAbsPath2 ) )
	rxTest:expectEqual( false, WFFileUtils.exists( externalSettingsAbsPath ) )
	
	developSession = LrmOzDevelopSession( catalog, photoId )
	
	local changes3 = {
		appliedCameraProfileDigest = "54650a341b5b5ccae8442d0b43a92bce",
		cameraModelName = "JPEG",
		cameraProfileFileName = "JPEG Embedded.dcp",
		cameraProfileLink = "",
		croppedHeight = 960,
		croppedWidth = 1280,
		crsVersion = "12.3",
		fromDefaults = false,
		userOrientation = 8,
		thumbnail = fakeThumbnail,
		highDpiThumbnail = fakeHighDpiThumbnail,
		xmpCameraRaw = '<xmp/>'
	}
	rxTest:expectSingleValue( saveSettingsChanges( developSession, changes3 ), true )
	
	xmpDevelopPathObserver:expectDataWithinTime( 3, nil )
		
	rxTest:expectEqual( false, WFFileUtils.exists( externalSettingsAbsPath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( externalSettingsAbsPath2 ) )
end

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

return WFRxTestCase.wrapSuite( LrmOzDevelopSessionTest )
