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

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 WFRxTestCase = require 'WFRxTestCase'

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

	-- WF.managed_catalog
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatAlbumTestUtils = require 'WFCatAlbumTestUtils'

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

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

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

local LrmLibraryAlbumAssetTest = {}

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

local function createMockedLibrary( rxTest )

	local catalog, wfCatalog = LrmCatalogTestHelper.makeCatalogService( rxTest )

	rxTest:finally( function()
		catalog:close()
	end )

	local mockedLibrary = {
		catalog = catalog,
		_wfCatalogStream = Rx.Observable.just( wfCatalog )
	}

	return mockedLibrary, wfCatalog

end

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

local function makeAdderOfTopicAlbum( rxTest, wfCatalog )

	local counter = 1

	return function( parentId )

		local albumName = string.format( "Album %d", counter )

		local docId = KSIdGenerator.uuidInLowercaseHex()

		local albumDoc = {

			_id = docId,
			type = 'album',
			subtype = 'topic',
			name = albumName,
			parent = parentId and {
				id = parentId
			}

		}
	
		rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )

		counter = counter + 1

		return docId

	end

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 albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum'
	}

	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )

	rxTest:waitFor( WFCatAlbumTestUtils.insertAlbumAssets( rxTest, wfCatalog, albumId, 200 ) )

	local assetIds = rxTest:getFirstValue( wfCatalog:indexStore():queryOnce {
			sql = 'SELECT assetId FROM album_asset WHERE albumId = ?', 
			singleColumnQuery = true,
			quiesceUntilUpToDate = true,
			albumId
		} )

	rxTest:expectEqual( #assetIds, 200 )

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

	rxTest:expectSingleValue( wfCatalog:indexStore():queryOnce {
			sql = "SELECT assetId FROM album_asset WHERE albumId = ?", 
			singleColumnQuery = true,
			quiesceUntilUpToDate = true,
			albumId
		},
		{} )

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 albumDoc = {
		_id = albumId,
		type = 'album',
		subtype = 'collection',
		name = 'testalbum'
	}

	rxTest:waitFor( wfCatalog:docStore():setDocValue( albumDoc ) )

	rxTest:waitFor( WFCatAlbumTestUtils.insertAlbumAssets( rxTest, wfCatalog, albumId, 200 ) )

	local assetIds = rxTest:getFirstValue( wfCatalog:indexStore():queryOnce {
			sql = 'SELECT assetId FROM album_asset WHERE albumId = ?',
			singleColumnQuery = true,
			quiesceUntilUpToDate = true,
			albumId
		} )

	rxTest:expectEqual( #assetIds, 200 )

	rxTest:waitFor( WFCatTrash.moveAssetsToTrash( wfCatalog, assetIds ) )

	rxTest:expectSingleValue( wfCatalog:indexStore():queryOnce {
			sql = 'SELECT album_asset.assetId FROM album_asset INNER JOIN coreInfo ON album_asset.assetId = coreInfo.docId WHERE albumId = ?',
			albumId
		}, {} )

	rxTest:expectSingleValue( wfCatalog:indexStore():queryOnce {
			sql = 'SELECT docId FROM coreInfo',
			albumId
		},
		{} )

end

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

function LrmLibraryAlbumAssetTest.rxTest_BestPhotos_DeleteCluster( rxTest )

	rxTest:setTimeLimit( 10 )
	
	local mockedLibrary = createMockedLibrary( rxTest )
	local wfCatalog = mockedLibrary.catalog

	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	-- Create a cluster document.
	
	local addAlbumFn = makeAdderOfTopicAlbum( rxTest, wfCatalog )
	
	-- Create a cluster document.
	
	local clusterId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( docStore:setDocValue( {
		_id = clusterId,
		type = 'album',
		subtype = 'cluster'
	} ) )
	
	
	addAlbumFn( clusterId )
	addAlbumFn( clusterId )
	addAlbumFn( clusterId )
	addAlbumFn( clusterId )
	addAlbumFn( clusterId )

	-- Create random album

	rxTest:waitFor( docStore:applyOverlay {
		_id = KSIdGenerator.uuidInLowercaseHex(),
		type = 'album',
		subtype = 'collection',
		name = "Album 1",
	} )
	
	
	rxTest:expectSingleValue(
		indexStore:queryOnce( { sql = "SELECT * FROM albums" } )
			:map( function( resultSet )
				return #resultSet
			end ),
		7 )
	
	rxTest:waitFor( LrmLibraryAlbumAssetModelImp.deleteCluster( mockedLibrary, clusterId ).value )
	
	-- Verify that only the cluster and its topic albums are deleted.
	local obs = rxTest:observe(
		indexStore:queryOnce( { 
			sql = "SELECT count(*) FROM albums",
			singleColumnQuery = true
		} )
		:map( function( resultSet )
			return resultSet[ 1 ]
		end ) )

	obs:expectDataWithinTime( 5, 1 )

end

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

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

return WFRxTestCase.wrapSuite( 'LrmLibraryAlbumAssetTest', LrmLibraryAlbumAssetTest )
