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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 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.self_test
local WFAsyncTestCase = require 'WFAsyncTestCase'
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'



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

	-- WF.core
local WFCatTrash = require 'WFCatTrash'

	-- Lrmobile_models
local LrmCatalogTestHelper = require 'LrmCatalogTestHelper'	
local LrmLibraryAlbumAssetModelImp = require 'LrmLibraryAlbumAssetModelImp'
local LrmDocValueTestFactory = require 'LrmDocValueTestFactory'


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

local LrmLibraryAlbumAssetTest = {}

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

local function createMockedLibrary( rxTest )

	local catalog, wfCatalog = LrmCatalogTestHelper.makeCatalogService()
	
	rxTest:finally( function()
		catalog:close()
	end )
	
	local mockedLibrary = {
		catalog = catalog,
		_wfCatalogStream = Rx.Observable.just( wfCatalog )
	}

	return mockedLibrary, wfCatalog
	
end 

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

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

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

end

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

function LrmLibraryAlbumAssetTest.rxTestAddAssetToAlbum( rxTest )

	rxTest:setTimeLimit( 10 )

	local mockedLibrary, wfCatalog = createMockedLibrary( rxTest )

	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDoc = buildDocValue( rxTest, wfCatalog, assetId )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	rxTest:expectSingleValue( 
		LrmLibraryAlbumAssetModelImp.addAssetsToAlbum( mockedLibrary, albumId, { assetId } ).value
		, { state = true } 
	)
	
	rxTest:observe( wfCatalog:indexStore():query{
		sql = "SELECT assetId FROM album_asset WHERE albumId = ?", albumId
	} )
	:expectDataWithinTime( 2, {{ assetId }} )
	:dispose()
	
end

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

function LrmLibraryAlbumAssetTest.rxTestRemoveAssetFromAlbum( rxTest )

	rxTest:setTimeLimit( 10 )

	local mockedLibrary, wfCatalog = createMockedLibrary( rxTest )

	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDoc = buildDocValue( rxTest, wfCatalog, assetId )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum',
		cover = {
			id = assetId,
		}
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	local albumAssetDoc = {
		_id = albumAssetId,
		type = 'album_asset',
		album = {
			id = albumId,
		},
		asset = {
			id = assetId,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc ) )
	
	rxTest:expectSingleValue( 
		LrmLibraryAlbumAssetModelImp.removeAssetsFromAlbum( mockedLibrary, albumId, { assetId } ).value
		, { state = true } 
	)
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = KSTableUtils.derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil and not albumDocValue.cover
		end )
	, true )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( albumAssetId )
		:map( function( albumAssetDocValue )
			if albumAssetDocValue then
				albumAssetDocValue._revId = nil
			end
			return albumAssetDocValue
		end )
	, {
		_id = albumAssetId,
		_empty = true,
		_deleted = true
	} )
	
end

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

function LrmLibraryAlbumAssetTest.rxTestRemoveAssetsFromAlbum( rxTest )

	rxTest:setTimeLimit( 10 )

	local mockedLibrary, wfCatalog = createMockedLibrary( rxTest )

	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local assetIds = {}
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	rxTest:waitFor( LrmDocValueTestFactory.insertAlbumAssets( wfCatalog:docStore(), albumId, 200 ) )

	rxTest:waitFor( wfCatalog:indexStore():queryOnce{
			sql = 'SELECT assetId FROM album_asset WHERE albumId = ?', albumId
		}
		:map( function( rows ) 
			for i, row in pairs( rows ) do
				assetIds[ i ] = row[ 1 ]
			end
		end ) )

	rxTest:expectEqual( #assetIds, 200 )

	rxTest:expectSingleValue( 
		LrmLibraryAlbumAssetModelImp.removeAssetsFromAlbum( mockedLibrary, albumId, assetIds ).value
		, { state = true } 
	)

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

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

function LrmLibraryAlbumAssetTest.rxTestMoveAssetToAlbum( rxTest )

	rxTest:setTimeLimit( 10 )

	local mockedLibrary, wfCatalog = createMockedLibrary( rxTest )

	local fromAlbumId = KSIdGenerator.uuidInLowercaseHex()
	local toAlbumId = KSIdGenerator.uuidInLowercaseHex()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDoc = buildDocValue( rxTest, wfCatalog, assetId )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDoc ) )
	
	local fromAlbumDoc = {
		_id = fromAlbumId,
		type = 'album',
		subtype = 'collection',
		name = 'fromAlbum',
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( fromAlbumDoc ) )
	
	local toAlbumDoc = {
		_id = toAlbumId,
		type = 'album',
		subtype = 'collection',
		name = 'fromAlbum',
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( toAlbumDoc ) )
	
	local albumAssetDoc = {
		_id = albumAssetId,
		type = 'album_asset',
		album = {
			id = fromAlbumId,
		},
		asset = {
			id = assetId,
		},
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumAssetDoc ) )
	
	local fromAlbumAssetObserve = rxTest:observe( wfCatalog:indexStore():query{
			sql = 'SELECT assetId FROM album_asset WHERE albumId == ?', fromAlbumId
		} )
	
	local toAlbumAssetObserve = rxTest:observe( wfCatalog:indexStore():query{
			sql = 'SELECT assetId FROM album_asset WHERE albumId == ?', toAlbumId
		} )
		
	fromAlbumAssetObserve:expectDataWithinTime( 2, {{ assetId }} )
	toAlbumAssetObserve:expectDataWithinTime( 2, {} )
	
	rxTest:expectSingleValue( 
		LrmLibraryAlbumAssetModelImp.moveAssetsToAlbum( mockedLibrary, fromAlbumId, toAlbumId, { assetId } ).value
		, { state = true } 
	)
	
	fromAlbumAssetObserve:expectDataWithinTime( 2, {} )
		:dispose()
	
	toAlbumAssetObserve:expectDataWithinTime( 2, {{ assetId }} )
		:dispose()
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( fromAlbumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = KSTableUtils.derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( toAlbumId )
		:map( function( albumDocValue )
			local userUpdatedTimestamp = KSTableUtils.derefOpt( albumDocValue, 'userUpdated' )
			return userUpdatedTimestamp ~= nil
		end )
	, true )
	
	
	
end

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

function LrmLibraryAlbumAssetTest.rxTestDeleteAssets( rxTest )
	
	rxTest:setTimeLimit( 10 )

	local _, wfCatalog = createMockedLibrary( rxTest )

	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local assetIds = {}
	
	local albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )
	
	rxTest:waitFor( LrmDocValueTestFactory.insertAlbumAssets( wfCatalog:docStore(), albumId, 200 ) )

	rxTest:waitFor( wfCatalog:indexStore():queryOnce{
			sql = 'SELECT assetId FROM album_asset WHERE albumId = ?', albumId
		}
		:map( function( rows ) 
			for i, row in pairs( rows ) do
				assetIds[ i ] = row[ 1 ]
			end
		end ) )

	rxTest:expectEqual( #assetIds, 200 )
	
	rxTest:waitFor( WFCatTrash.moveAssetsToTrash( wfCatalog, assetIds ) )
	
	rxTest:observe( wfCatalog:indexStore():query{
			sql = 'SELECT album_asset.assetId FROM album_asset INNER JOIN coreInfo ON album_asset.assetId = coreInfo.docId WHERE albumId = ?', 
			albumId
		} )
		:expectDataWithinTime( 2, {} )
		:dispose()
		
	rxTest:observe( wfCatalog:indexStore():query{
			sql = 'SELECT docId FROM coreInfo', 
			albumId
		} )
		:expectDataWithinTime( 2, {} )
		:dispose()
		
end

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

if require 'WFPlatformInfo'.isDesktop then return {} end

return WFRxTestCase.wrapSuite( LrmLibraryAlbumAssetTest )
