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

WFCatAssetTest.lua

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

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

NOTICE: All information contained herein is, and remains 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 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 Systems Incorporated.

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

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

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFModelsUtils = require 'WFModelsUtils'
local WFCatCollaborationActivityTestUtils = require "WFCatCollaborationActivityTestUtils"

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

local createFakeWFCatalog = WFCatMockCatalog.createFakeWFCatalog

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

local randomDocId = '7206c3ae9a094d69861ee8983e95085d'

local kDefaultDescription = "WFCatTask"

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

return function( optSubmodelsByImplementation, maybeExistingTestClass )

	----------------------------------------------------------------------------
	
	local function callFunctionOrSubmodel( rxTest, wfCatalog, fnNamespace, fnName, ... )
	
		return WFModelsUtils.callFunctionOrSubmodel( rxTest, optSubmodelsByImplementation, wfCatalog, fnNamespace, fnName, ... )
					
	end

	----------------------------------------------------------------------------
	
	local WFCatAssetTest = maybeExistingTestClass or {}
	
	----------------------------------------------------------------------------
		
	function WFCatAssetTest.rxTestRatings( rxTest )

		rxTest:setTimeLimit( 5 )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		rxTest:expectSingleValue(

			docStore:setDocValue {
					_id = randomDocId,
					type = 'asset',
					subtype = 'image',
					_localOnly = {
						files = {
							proxy = {
								pano = {
									relativePath = 'foo',
									volumeGuid = 'bar'
								}
							}
						}
					},
					importSource = {
						filePath = '/path/',
						originalHeight = 150,
						originalWidth = 100,
					}
				},

			':ignore:' )

		rxTest:expectSingleValue( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset',
				'setRatings', fakeWFCatalog, { 1 }, 4 ),
			':ignore:' )

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset',
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
					assetIds = { 1 },
					ratings = true,
				} 
				) )
		:expectDataWithinTime( 3, {
			{
				rating = 4,
			},
		} )

	end
	
	--------------------------------------------------------------------------------

	function WFCatAssetTest.rxTestFlags( rxTest )

		rxTest:setTimeLimit( 5 )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		rxTest:expectSingleValue(

			docStore:setDocValue {
					_id = randomDocId,
					type = 'asset',
					subtype = 'image',
					_localOnly = {
						files = {
							proxy = {
								pano = {
									relativePath = 'foo',
									volumeGuid = 'bar'
								}
							}
						}
					},
					importSource = {
						filePath = '/path/',
						originalHeight = 150,
						originalWidth = 100,
					}
				},

			':ignore:' )

		rxTest:expectSingleValue( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setFlags', fakeWFCatalog, { 1 }, 'pick', '2001' ),
			':ignore:' )

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
				assetIds = { 1 },
				flags = true,
				coalesce = true,
			} ) )
			:expectDataWithinTime( 3, {
				flag = 'pick',
				numberOfAssets = 1,
			} )

	end

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

	function WFCatAssetTest.rxTestKeywordsSingleAsset( rxTest )

		local timeOut = 5
		
		rxTest:setTimeLimit( timeOut )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		docStore:setDocValue {
			_id = "doc_1",
			type = 'asset',
			subtype = 'image',
			_localOnly = {
				files = {
					proxy = {
						pano = {
							relativePath = 'foo',
							volumeGuid = 'bar'
						}
					}
				}
			},
		}

		local obs = rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setKeywords', fakeWFCatalog, { 1 }, { "KeywordA" } )
				:map( function( data )
					return data
				end )
			)
		
		obs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			percentComplete = 0,
			processedCount = 0,
			totalCount = 1,
		})
		
		obs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			percentComplete = 1,
			processedCount = 1,
			totalCount = 1,
		})
		
		obs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			extraInfo = {
				totalCount = 1,
				undoToken = 7,
			},
			percentComplete = 1,
			processedCount = 1,
			totalCount = 1,
		})
		
		obs:expectCompleted()
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
					assetIds = { 1 },
					keywords = true,
				} ) )
			:expectData {
				{
					keywords = {
						"KeywordA",
					},
				},
			}
		
	end

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

	function WFCatAssetTest.rxTestKeywordsMultiAssets( rxTest )

		rxTest:setTimeLimit( 5 )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		docStore:bulkSetDocValue {
			{
				_id = "doc_1",
				type = 'asset',
				subtype = 'image',
				_localOnly = {
					files = {
						proxy = {
							pano = {
								relativePath = 'foo',
								volumeGuid = 'bar'
							}
						}
					}
				},
			},
			
			{
				_id = "doc_2",
				type = 'asset',
				subtype = 'image',
				_localOnly = {
					files = {
						proxy = {
							pano = {
								relativePath = 'foo',
								volumeGuid = 'bar'
							}
						}
					}
				},
			}
		}

		local obs = rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setKeywords', fakeWFCatalog, { 1 }, { "KeywordA", "KeywordB" } )
			:takeLast( 0 ) )
		
		obs:expectCompleted()
		
		local obs2 = rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setKeywords', fakeWFCatalog, { 2 }, { "KeywordA" } )
			:takeLast( 0) )
		
		obs2:expectCompleted()
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
					assetIds = { 1 , 2 },
					keywords = true,
				} ) )
			:expectData {
				{
					keywords = {
						"KeywordB",
						"KeywordA",
					},
				},
				{
					keywords = {
						"KeywordA",
					},
				},
			}
		
	end

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

	function WFCatAssetTest.rxTestKeywordsDelete( rxTest )

		local timeOut = 10
		
		rxTest:setTimeLimit( timeOut )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		docStore:setDocValue {
			_id = "doc_1",
			type = 'asset',
			subtype = 'image',
			_localOnly = {
				files = {
					proxy = {
						pano = {
							relativePath = 'foo',
							volumeGuid = 'bar'
						}
					}
				}
			},
		}

		-- Add three keywords for test
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setKeywords', fakeWFCatalog, { 1 }, { "KeywordA", "KeywordB", "KeywordC" } ) )
		
		-- Test delete keywords
		local deleteKeywordObs = rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setKeywords', fakeWFCatalog, { 1 }, { "KeywordA" }, true ) 
				:map( function( data )
					return data
				end )
			)
		
		deleteKeywordObs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			percentComplete = 0,
			processedCount = 0,
			totalCount = 1,
		})
		
		deleteKeywordObs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			percentComplete = 1,
			processedCount = 1,
			totalCount = 1,
		})
		
		deleteKeywordObs:expectDataWithinTime( timeOut, {
			description = kDefaultDescription,
			errorCount = 0,
			extraInfo = {
				totalCount = 1,
				undoToken = 4,
			},
			percentComplete = 1,
			processedCount = 1,
			totalCount = 1,
		})
		
		deleteKeywordObs:expectCompleted()

		-- Check the result data
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1 },
				keywords = true,
			} )
			:map( function( info )
			
				 table.sort( info[1].keywords )
				 return info
			
			end )
			)
			:expectData {
				{
					keywords = { "KeywordB", "KeywordC" },
				},
			}

	end

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

	function WFCatAssetTest.rxTestCommentsFromIndexStore( rxTest )
		
		local timeOut = 5
		
		rxTest:setTimeLimit( timeOut )
		
		local fakeWFCatalog = WFCatCollaborationActivityTestUtils.createFakeWFCatalog( rxTest )
		
		local docStore = fakeWFCatalog:docStore()
		
		local albumInfo, assetInfo = WFCatCollaborationActivityTestUtils.createSharedAlbumWithAsset( rxTest, fakeWFCatalog )
		
		local currUserId = fakeWFCatalog:ozUserId()

			-- Simulate already added comment
		
		local comments = {
			WFCatCollaborationActivityTestUtils.createComment( albumInfo.spaceId, assetInfo.globalId, currUserId, "comment1" ),
		}
		
		rxTest:expectOnlyCompleted(
			docStore:bulkSetDocValue( comments )
				:takeLast( 0 ) )
		
			-- Collect assetInfo from the index store
			
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
				assetIds = { assetInfo.localId },
				comments = true,
				albumId = albumInfo.localId
			} ) )
		
			:expectDataWithinTime( timeOut, {
				{
					comment = true,
				},
			} )
			
	end

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

	function WFCatAssetTest.rxTestFavoritesFromIndexStore( rxTest )
		
		local timeOut = 5
		
		rxTest:setTimeLimit( timeOut )
		
		local fakeWFCatalog = WFCatCollaborationActivityTestUtils.createFakeWFCatalog( rxTest )
		
		local docStore = fakeWFCatalog:docStore()
		
		local albumInfo, assetInfo = WFCatCollaborationActivityTestUtils.createSharedAlbumWithAsset( rxTest, fakeWFCatalog )
		
		local currUserId = fakeWFCatalog:ozUserId()

			-- Simulate already added favorite
		
		local favoriteDoc1 = WFCatCollaborationActivityTestUtils.createFavorite( albumInfo.spaceId, assetInfo.globalId, currUserId )
		rxTest:expectOnlyCompleted(
			docStore:bulkSetDocValue( { favoriteDoc1 } )
				:takeLast( 0 ) )
		
			-- Collect assetInfo from the index store
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromIndexStore', fakeWFCatalog, {
				assetIds = { assetInfo.localId },
				favorites = true,
				albumId = albumInfo.localId
			} ) )
		
			:expectDataWithinTime( timeOut, {
				{
					favorite = true,
				},
			} )
		
	end

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

	function WFCatAssetTest.rxTestRatingsFromDocStore( rxTest )

		rxTest:setTimeLimit( 5 )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		rxTest:expectSingleValue(

			docStore:setDocValue {
					_id = randomDocId,
					type = 'asset',
					subtype = 'image',
					_localOnly = {
						files = {
							proxy = {
								pano = {
									relativePath = 'foo',
									volumeGuid = 'bar'
								}
							}
						}
					},
					importSource = {
						filePath = '/path/',
						originalHeight = 150,
						originalWidth = 100,
					},
				},

			':ignore:' )

		rxTest:expectSingleValue( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setRatings', fakeWFCatalog, { 1 }, 4 ), ':ignore:' )

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1 },
				ratings = true,
			} ) )
			:expectDataWithinTime( 3, {
				{
					rating = 4,
				},
			} )

	end
	--------------------------------------------------------------------------------

	function WFCatAssetTest.rxTestFlagsFromDocStore( rxTest )

		rxTest:setTimeLimit( 5 )

		local fakeWFCatalog = createFakeWFCatalog( rxTest )

		local docStore = fakeWFCatalog:docStore()

		rxTest:expectSingleValue(

			docStore:setDocValue {
					_id = randomDocId,
					type = 'asset',
					subtype = 'image',
					_localOnly = {
						files = {
							proxy = {
								pano = {
									relativePath = 'foo',
									volumeGuid = 'bar'
								}
							}
						}
					},
					importSource = {
						filePath = '/path/',
						originalHeight = 150,
						originalWidth = 100,
					},
				},

			':ignore:' )

		rxTest:expectSingleValue( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'setFlags', fakeWFCatalog, { 1 }, 'pick', '2001' ),
			':ignore:' )

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1 },
				flags = true,
			} ) )
			:expectDataWithinTime( 3, {
				{
					flag = 'pick',
				}
			} )

	end

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

	local function addTestAsset( rxTest, catalog, localId, params )
		
		rxTest:expectSingleValue(

			catalog:docStore():bulkSetDocValue {
				{
					_id = KSIdGenerator.uuidInLowercaseHex(),
					_localId = localId,
					type = "asset",
					subtype = "image",
					_localOnly = {
						files = {
							original = {
								master = {
									volumeGuid = string.format( 'volume guid %s', localId ),
									relativePath = string.format( 'local path %s', localId ),
								}
							}
						}
					},
					_spaceId = params.spaceId,
					_serverProvidedMetadata = {
						importedByUser = {
							id = params.importedByUser,
						},
					},
					importSource = {
						fileName = params.maybeFileName,
					},
					captureDate = params.maybeCaptureDate,
					xmp = {
						exif = {
							DateTimeOriginal = params.maybeDateTimeOriginal,
						},
						photoshop = {
							DateCreated = params.maybeDateCreated,
						},
						xmp = {
							CreateDate = params.maybeCreateDate,
						}
					},
				},
			},

			':ignore:' )
	end

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

	function WFCatAssetTest.rxTestCollectCaptureDateTimeRangeForAssets( rxTest )

		local timeOut = 10
			
		rxTest:setTimeLimit( timeOut )
		
		local fakeWFCatalog = createFakeWFCatalog( rxTest )
		
		addTestAsset( rxTest, fakeWFCatalog, 1, {
			maybeCaptureDate = '1904-01-01T00:00Z',
			maybeDateTimeOriginal = '1904-01-01T00:00Z',
			maybeDateCreated = '1904-01-01T00:00Z',
			maybeCreateDate = '1904-01-01T00:00Z',
		} )
		
		addTestAsset( rxTest, fakeWFCatalog, 1, {
			maybeCaptureDate = '2004-01-01T00Z',
			maybeDateTimeOriginal = '2004-01-01T00Z',
			maybeDateCreated = '2004-01-01T00Z',
			maybeCreateDate = '2004-01-01T00Z',
		} )

		local assetIds = { 1, 2 }
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectCaptureDateTimeRangeForAssets', fakeWFCatalog, assetIds ) )
			:expectDataWithinTime( timeOut, {
				captureDateTimeRange = {
					maxCaptureDate = "2004-01-01T00:00:00Z",
					maxTime = 20040101000000,
					minCaptureDate = "1904-01-01T00:00:00Z",
					numOfEmptyCaptureDate = 0,
					minTime = 19040101000000,
					processedImages = 2,
				},
				numberOfAssets = 2,
			} )

	end

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

	function WFCatAssetTest.rxTestSharedInfoForAssetsFromDocStore( rxTest )

		local timeOut = 10
			
		rxTest:setTimeLimit( timeOut )
		
		local fakeWFCatalog = createFakeWFCatalog( rxTest )
		
		addTestAsset( rxTest, fakeWFCatalog, 1, {
			maybeCaptureDate = '1904-01-01T00:00Z',
			maybeDateTimeOriginal = '1904-01-01T00:00Z',
			maybeDateCreated = '1904-01-01T00:00Z',
			maybeCreateDate = '1904-01-01T00:00Z',
			importedByUser = 'foo',
		} )
		
		addTestAsset( rxTest, fakeWFCatalog, 1, {
			maybeCaptureDate = '2004-01-01T00Z',
			maybeDateTimeOriginal = '2004-01-01T00Z',
			maybeDateCreated = '2004-01-01T00Z',
			maybeCreateDate = '2004-01-01T00Z',
			spaceId = 'bar',
		} )

		local assetIds = { 1, 2 }
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = assetIds,
				importedByUser = true,
				spaceInfo = true,
			} ) )
			:expectDataWithinTime( timeOut, {
				{
					importedByUser = 'foo',
				},
				{
					spaceId = 'bar',
					importedByUser = fakeWFCatalog:ozUserId(),
				},
			} )

	end

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

	function WFCatAssetTest.rxTestUnsupportedFormatForAssets( rxTest )
		local timeOut = 20
		
		rxTest:setTimeLimit( timeOut )
		
		local fakeWFCatalog = createFakeWFCatalog( rxTest )
		
		addTestAsset( rxTest, fakeWFCatalog, 1, {
			maybeFileName = 'File1.JPG'
		} )
		
		addTestAsset( rxTest, fakeWFCatalog, 2, {
			maybeFileName = 'File2.HEIC'
		} )

		addTestAsset( rxTest, fakeWFCatalog, 3, {
			maybeFileName = 'File2.PNG'
		} )

		local NmbAcr = require 'NmbAcr'
		local isHeifSupported = NmbAcr.WFCrInfo.supportsHeic()
		
		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1, 2, 3 },
				isUnsupportedFormat = true,
			} ) )
			:expectDataWithinTime( timeOut, {
				{ isUnsupportedFormat = false, },
				{ isUnsupportedFormat = not isHeifSupported, },
				{ isUnsupportedFormat = false, },
			} )	

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1, 2, 3 },
				isUnsupportedFormat = true,
				coalesce = true,
			} ) )
			:expectDataWithinTime( timeOut, {
				numberOfAssets = 3,
				isUnsupportedFormat = not isHeifSupported,
			} )	

		rxTest:observe( callFunctionOrSubmodel(
				rxTest, fakeWFCatalog,
				'WFCatAsset', 
				'collectInfoForAssetsFromDocStore', fakeWFCatalog, {
				assetIds = { 1, 3 },
				isUnsupportedFormat = true,
				coalesce = true,
			} ) )
			:expectDataWithinTime( timeOut, {
				numberOfAssets = 2,
				isUnsupportedFormat = false,
			} )	
			
	end

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

	if not require 'WFPlatformInfo'.hasACR then
		WFCatAssetTest.rxTestUnsupportedFormatForAssets = nil
	end

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

	return maybeExistingTestClass and WFCatAssetTest 
			or WFRxTestCase.wrapSuite( WFCatAssetTest )
	
	--============================================================================--
	
end
