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

LrmAlbumAssetUtilsTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2020 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.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local KSTableUtils = require 'KSTableUtils'

	-- WF.managed_catalog
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local LrmAlbumAssetUtils = require 'LrmAlbumAssetUtils'

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

local derefOpt = KSTableUtils.derefOpt

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

local LrmAlbumAssetUtilsTest = {}

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

local function createFakeWFCatalog( rxTest )

	local optArgs = {}
	optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'

	return WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, optArgs )
	
end 

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

local function buildDocValue( rxTest, wfCatalog, assetId, overrides )

	assetId = assetId or KSIdGenerator.uuidInLowercaseHex()
	
	return WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, overrides )

end

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

function LrmAlbumAssetUtilsTest.rxTestRemoveAssetsFromOwnAlbum( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetDoc = {
		_id = KSIdGenerator.uuidInLowercaseHex(),
		type = 'album_asset',
		album = {
			id = albumId,
		},
		asset = {
			id = assetId,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc ) )
	
	local albumAssetObserve = rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	
	albumAssetObserve:expectDataWithinTime( 2, {{ assetId }} )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.removeAssetsFromOwnAlbum( wfCatalog, albumId, { assetId } )
		, { assetId } )
		
	albumAssetObserve:expectDataWithinTime( 2, {} )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestRemoveAssetsFromOwnAlbum_assetNotInAlbum( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetObserve = rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.removeAssetsFromOwnAlbum( wfCatalog, albumId, { assetId } )
		, {} )
		
	albumAssetObserve:expectDataWithinTime( 2, {} )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp == nil
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestRemoveAssetsFromOwnAlbum_removeCoverAsset( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo',
		cover = {
			id = assetId
		}
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetDoc = {
		_id = KSIdGenerator.uuidInLowercaseHex(),
		type = 'album_asset',
		album = {
			id = albumId,
		},
		asset = {
			id = assetId,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc ) )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			return derefOpt( albumDocValue, 'cover', 'id' )
		end )
	, assetId )
	
	local albumAssetObserve = rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	
	albumAssetObserve:expectDataWithinTime( 2, {{ assetId }} )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.removeAssetsFromOwnAlbum( wfCatalog, albumId, { assetId } )
		, { assetId } )
		
	albumAssetObserve:expectDataWithinTime( 2, {} )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil and not albumDocValue.cover
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestRemoveAssetsFromOwnAlbum_albumNotExists( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectOnlyError( LrmAlbumAssetUtils.removeAssetsFromOwnAlbum( wfCatalog, albumId, { assetId } )
		, 'invalidAlbum' )

	rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	:expectData( {} )
	:dispose()

end

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

function LrmAlbumAssetUtilsTest.rxTestAddAssetsToOwnAlbum( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.addAssetsToOwnAlbum( wfCatalog, albumId, { assetId } )
		, { assetId } )
		
	rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	:expectDataWithinTime( 3, {{ assetId }} )
	:dispose()
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestAddAssetsToOwnAlbum_withOrder( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local order = { [ assetId ] = 'a' }
	rxTest:expectSingleValue( LrmAlbumAssetUtils.addAssetsToOwnAlbum( wfCatalog, albumId, { assetId }, order )
		, { assetId } )
		
	rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId, sortOrder FROM album_asset WHERE albumId = ?", albumId
	} )
	:expectDataWithinTime( 3, {{ assetId, 'a' }} )
	:dispose()
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestAddAssetsToOwnAlbum_existingAsset( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetDoc = {
		_id = KSIdGenerator.uuidInLowercaseHex(),
		type = 'album_asset',
		album = {
			id = albumId,
		},
		asset = {
			id = assetId,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc ) )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.addAssetsToOwnAlbum( wfCatalog, albumId, { assetId } )
		, {} )
		
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, false )

end

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

function LrmAlbumAssetUtilsTest.rxTestAddAssetsToOwnAlbum_assetExistenceCombination( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc1 = buildDocValue( rxTest, wfCatalog )
	local assetDoc2 = buildDocValue( rxTest, wfCatalog )
	
	local assetId1 = assetDoc1._id
	local assetId2 = assetDoc2._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc1 ) )
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc2 ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'foo'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetDoc1 = {
		_id = KSIdGenerator.uuidInLowercaseHex(),
		type = 'album_asset',
		album = {
			id = albumId,
		},
		asset = {
			id = assetId1,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc1 ) )
	
	local observeAlbumAsset = rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT COUNT(*) FROM album_asset WHERE albumId = ?", albumId
	} )
	
	observeAlbumAsset:expectDataWithinTime( 2, {{ 1 }} )
	
	rxTest:expectSingleValue( LrmAlbumAssetUtils.addAssetsToOwnAlbum( wfCatalog, albumId, { assetId1, assetId2 } )
		, { assetId2 } )

	observeAlbumAsset
	:expectDataWithinTime( 3, {{ 2 }} )
	:dispose()
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )

end

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

function LrmAlbumAssetUtilsTest.rxTestAddAssetsToOwnAlbum_albumNotExists( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetDoc = buildDocValue( rxTest, wfCatalog )
	local assetId = assetDoc._id
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local assetDocFromDocStore
	
	rxTest:waitFor( wfCatalog:docStore():docValue( assetId )
		:map( function( docValue )
			assetDocFromDocStore = docValue
			return true
		end ) )
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectOnlyError( LrmAlbumAssetUtils.addAssetsToOwnAlbum( wfCatalog, albumId, { assetId } )
		, 'invalidAlbum' )

	rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	:expectData( {} )
	:dispose()

end

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

return WFRxTestCase.wrapSuite( LrmAlbumAssetUtilsTest )