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

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

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

	-- RxLua
local Rx = require 'Rx'
local Observable = Rx.Observable

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

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

if not WFPlatformInfo.isMobile() then
       return {}
end

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

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

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

	-- WF.lrmobile
local LrmCatalogTestHelper = require 'LrmCatalogTestHelper'
local LrmConfig = require 'LrmConfig'
local LrmLibraryCacheModelImp = require 'LrmLibraryCacheModelImp'

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

local asKSPromise = WFRxPromiseBridge

local LrmLibraryCacheModelImpTest = {}

local catalog, wfCatalog

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

local function makeLocalOnly( testFilePath, testDataSize, epoch )

	local localOnly

	if WFPlatformInfo.isiOS then
		localOnly = {
			files = {
				master = {
					path = testFilePath,
					fileSize = testDataSize,
				},
				proxy = {
					path = testFilePath,
					fileSize = testDataSize,
				}
			}
		}
	else
		localOnly = {
			originalFilePath = testFilePath,
			original = {
				epoch = epoch,
				size = testDataSize,
			},
			proxy = {
				filePath = testFilePath,
				size = testDataSize,
				epoch = epoch
			}
		}
	end

	return localOnly

end

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

local function getExpectedPurgableCacheSizeForAlbum( expectedSize, albumId )
	
	local expectedData = expectedSize
	if WFPlatformInfo.isAndroid then
		expectedData = {
			size = expectedSize,
			albumId = albumId,		-- android expects albumid as it does not maintain state
		}
	end
	
	return expectedData
	
end

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

function LrmLibraryCacheModelImpTest.setUp()

	catalog, wfCatalog = LrmCatalogTestHelper.makeCatalogService()

end

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

function LrmLibraryCacheModelImpTest.tearDown()

	if catalog then
		catalog:close()
		catalog = nil
	end

	if wfCatalog then
		wfCatalog:close()
		wfCatalog = nil
	end

end

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

function LrmLibraryCacheModelImpTest.testPurgeableCacheSizeForAlbum( test )

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId2 = KSIdGenerator.uuidInLowercaseHex()
	
	local testFilePath = '/path'
	local testFilePath2 = '/path2'
	
	local function writeTestData( filePath, optData )
	
		local testData = KSData.make( optData or 'foo' )
		
		local size = KSData.length( testData )
		testData:close()
	
		return size
		
	end
	
	local testDataSize = writeTestData( testFilePath )
	local testDataSize2 = writeTestData( testFilePath2, 'foobar' )
	
	WFAsyncTestCase( test )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly = makeLocalOnly( testFilePath, testDataSize, 1 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId2,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly = makeLocalOnly( testFilePath2, testDataSize2, 2 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId,
				overlay = {
					subtype = 'collection',
					name = 'foo',
					_localOnly = {
						useOffline = true,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId2,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId2,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 9, albumId ) )
	
end

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

function LrmLibraryCacheModelImpTest.testMultipleAlbumPurgeSize( test )

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local albumId2 = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId2 = KSIdGenerator.uuidInLowercaseHex()
	local album2AssetId1 = KSIdGenerator.uuidInLowercaseHex()
	local album2AssetId2 = KSIdGenerator.uuidInLowercaseHex()
	
	local testFilePath = '/path'
	local testFilePath2 = '/path2'
	
	local function writeTestData( filePath, optData )
	
		local testData = KSData.make( optData or 'foo' )
		
		local size = KSData.length( testData )
		testData:close()
	
		return size
		
	end
	
	local testDataSize = writeTestData( testFilePath )
	local testDataSize2 = writeTestData( testFilePath2, 'foobar' )
	
	WFAsyncTestCase( test )
	
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath, testDataSize, 1 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId2,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath2, testDataSize2, 3 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId,
				overlay = {
					subtype = 'collection',
					name = 'foo',
					_localOnly = {
						useOffline = true,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId2,
				overlay = {
					subtype = 'collection',
					name = 'foo 2',
					_localOnly = {
						useOffline = false,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId2,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId2,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album2AssetId1,
				overlay = {
					album = {
						id = albumId2,
					},
					asset = {
						id = assetId,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album2AssetId2,
				overlay = {
					album = {
						id = albumId2,
					},
					asset = {
						id = assetId2,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId2 ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 0, albumId2 ) )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId,
				overlay = {
					subtype = 'collection',
					name = 'foo',
					_localOnly = {
						useOffline = false,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId2, LrmConfig.StrategyPreferProxy ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 9, albumId2 ) )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId2, LrmConfig.StrategyPreferMaster ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 9, albumId2 ) )
		
end

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

function LrmLibraryCacheModelImpTest.testMultiAlbumMultiAssetPurgeSize( test )

	local assetId1 = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local assetId3 = KSIdGenerator.uuidInLowercaseHex()
	local assetId4 = KSIdGenerator.uuidInLowercaseHex()
	
	local albumId1 = KSIdGenerator.uuidInLowercaseHex()
	local albumId2 = KSIdGenerator.uuidInLowercaseHex()
	
	local album1Asset1Id1 = KSIdGenerator.uuidInLowercaseHex()
	local album1Asset2Id2 = KSIdGenerator.uuidInLowercaseHex()
	
	local album2Asset3Id1 = KSIdGenerator.uuidInLowercaseHex()
	local album2Asset4Id2 = KSIdGenerator.uuidInLowercaseHex()
	
	local testFilePath = '/path'
	local testFilePath2 = '/path2'
	
	local function writeTestData( filePath, optData )
	
		local testData = KSData.make( optData or 'foo' )
		
		local size = KSData.length( testData )
		testData:close()
	
		return size
		
	end
	
	local testDataSize = writeTestData( testFilePath )
	local testDataSize2 = writeTestData( testFilePath2, 'foobar' )
	
	WFAsyncTestCase( test )
	
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId1,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath, testDataSize, 1 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId2,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath2, testDataSize2, 2 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId3,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath2, testDataSize2, 2 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId4,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath2, testDataSize2, 2 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId1,
				overlay = {
					subtype = 'collection',
					name = 'foo 1',
					_localOnly = {
						useOffline = true,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId2,
				overlay = {
					subtype = 'collection',
					name = 'foo 2',
					_localOnly = {
						useOffline = false,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album1Asset1Id1,
				overlay = {
					album = {
						id = albumId1,
					},
					asset = {
						id = assetId1,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album1Asset2Id2,
				overlay = {
					album = {
						id = albumId1,
					},
					asset = {
						id = assetId2,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album2Asset3Id1,
				overlay = {
					album = {
						id = albumId2,
					},
					asset = {
						id = assetId3,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = album2Asset4Id2,
				overlay = {
					album = {
						id = albumId2,
					},
					asset = {
						id = assetId4,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId1 ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 9, albumId1 ) )
		
		:waitFor( function()
		
			return LrmLibraryCacheModelImp.purgeableCacheSizeForAlbum( { catalog = catalog }, albumId2 ).value
			
		end )
		
		:continueWhenValueMatches( 'data', getExpectedPurgableCacheSizeForAlbum( 12, albumId2 ) )
		
end

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

-- @mark All Photos purgeable cache size

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

-- FIXME [jandrew 2025-03-11]: Disabled due to instability.

function LrmLibraryCacheModelImpTest.DISABLED_testAllPhotosPurgeableCacheSize( test )

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId2 = KSIdGenerator.uuidInLowercaseHex()
	
	local testFilePath = '/path'
	local testFilePath2 = '/path2'
	
	local function writeTestData( filePath, optData )
	
		local testData = KSData.make( optData or 'foo' )
		
		local size = KSData.length( testData )
		testData:close()
	
		return size
		
	end
	
	local testDataSize = writeTestData( testFilePath )
	local testDataSize2 = writeTestData( testFilePath2, 'foobar' )
	
	local mockModelSelf = {
		catalog = catalog,
		_wfCatalog = wfCatalog,
		_binaryDownloadStrategy = Observable.just( LrmConfig.StrategyPreferMaster )
	}

	WFAsyncTestCase( test )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath, testDataSize, 1 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'asset',
				docId = assetId2,
				overlay = {
					subtype = 'image',
					importSource = {
						originalWidth = 100,
						originalHeight = 100,
					},
					_localOnly =  makeLocalOnly( testFilePath2, testDataSize2, 2 ),
					_serverProvidedMetadata = {
						links = {
							[ '/rels/master' ] = {
								href = '/v1.0/123..'
							}
						}
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId,
				overlay = {
					subtype = 'collection',
					name = 'foo',
					_localOnly = {
						useOffline = true,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId,
					}
				}
			}
			
		end )
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album_asset',
				docId = albumAssetId2,
				overlay = {
					album = {
						id = albumId,
					},
					asset = {
						id = assetId2,
					}
				}
			}
			
		end )
		
		:waitFor( function()

			return LrmLibraryCacheModelImp.purgeableCacheSize( mockModelSelf ).value

				:call( asKSPromise )

		end )
		
		:continueWhenValueMatches( 'data', 0 ) -- Nothing is purgeable
		
		:waitFor( function()
		
			return catalog:docStore():applyOverlayToDocumentP {
			
				docType = 'album',
				docId = albumId,
				overlay = {
					subtype = 'collection',
					name = 'foo',
					_localOnly = {
						useOffline = false,
					}
				}
			}
			
		end )
		
		:waitFor( function()

			return LrmLibraryCacheModelImp.purgeableCacheSize( mockModelSelf ).value

				:call( asKSPromise )

		end )
		
		:continueWhenValueMatches( 'data', 9 ) -- Originals are purgeable. Proxies are not, because there are no local renditions.
		
end

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

return LrmLibraryCacheModelImpTest

