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

WFRxBatchedBulkOperationTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2019 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
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.

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

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

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFRxBatchedBulkOperation = require 'WFRxBatchedBulkOperation'
local WFRxScheduler = require "WFRxScheduler"

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


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

local createFakeWFCatalog = WFCatMockCatalog.createFakeWFCatalog


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

local WFRxBatchedBulkOperationTest = {}

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

local function batchedBulkHelper( rxTest, docStore )

	local assetIds = {}

	for i=1,100 do

		local assetId = KSIdGenerator.uuidInLowercaseHex()

		rxTest:expectSingleValue(

			docStore:setDocValue {
					_id = assetId,
					type = 'asset',
					subtype = 'jpeg',
					_localOnly = {
						batchTest = true,
					}
				},

			':ignore:' )

		assetIds[ i ] = assetId

	end

	return assetIds

end

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

function WFRxBatchedBulkOperationTest.rxTestBasic( rxTest )

	rxTest:setTimeLimit( 10 )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	local docStore = fakeWFCatalog:docStore()

	local assetIds = batchedBulkHelper( rxTest, docStore )

	-- Check that the local only annotation is present
	for _, assetId in ipairs( assetIds ) do

		local batchTest = docStore:docValue( assetId )
			:pluck( "_localOnly", "batchTest" )

		rxTest:expectSingleValue( batchTest, true )

	end

	local batchSizesToTest = { 1, 2, 3, 49, 50, 51, 99, 100, 101, 200 }
	for _, batchSize in ipairs( batchSizesToTest ) do

		rxTest:expectSingleValue( WFRxBatchedBulkOperation( "rxTestBasic", docStore, assetIds, batchSize, 1, function( batchOfDocValues )

			local bulkOverlay = {}
			for i, docValue in ipairs( batchOfDocValues ) do
				bulkOverlay[ i ] = {
					_id = docValue._id,
					_localOnly = {
						-- Set batchTest to batchSize as it will be unique for the run.
						batchTest = batchSize,
					}
				}
			end

			return docStore:bulkApplyOverlay( bulkOverlay )

		end )
		:scan( function( totalProcessed, bulkApplyOverlayResults )
			totalProcessed = totalProcessed + #bulkApplyOverlayResults
			return totalProcessed
		end, 0 )
		:takeLast( 1 ), #assetIds )

		-- Check that the local only annotation is gone
		for _, assetId in ipairs( assetIds ) do

			rxTest:expectSingleValue( docStore:docValue( assetId )
				:pluck( "_localOnly", "batchTest" ), batchSize )

		end

	end

end

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

function WFRxBatchedBulkOperationTest.rxTestSimultaneous( rxTest )

	rxTest:setTimeLimit( 10 )

	local fakeWFCatalog = createFakeWFCatalog( rxTest )

	local docStore = fakeWFCatalog:docStore()

	local assetIds = batchedBulkHelper( rxTest, docStore )

	-- Check that the local only annotation is present
	for _, assetId in ipairs( assetIds ) do

		local batchTest = docStore:docValue( assetId )
			:pluck( "_localOnly", "batchTest" )

		rxTest:expectSingleValue( batchTest, true )

	end

	local kRequestedSimultaneous = 3
	local kBatchSize = 5
	local kNumExpectedBatches = 20
	local numSimultaneous = 0
	local maxSimultaneous = 0

	local function bulkOperation( batchOfDocValues )

		numSimultaneous = numSimultaneous + 1
		maxSimultaneous = math.max( maxSimultaneous, numSimultaneous )

		local bulkOverlay = {}
		for i, docValue in ipairs( batchOfDocValues ) do
			bulkOverlay[ i ] = {
				_id = docValue._id,
				_localOnly = {
					-- Set batchTest to batchSize as it will be unique for the run.
					batchTest = kBatchSize,
				}
			}
		end

		return docStore:bulkApplyOverlay( bulkOverlay )
		:delay( 0.1, WFRxScheduler.sharedScheduler() )
		:tap( function()
			numSimultaneous = numSimultaneous - 1
		end )

	end

	rxTest:expectSingleValue(
		WFRxBatchedBulkOperation( "rxTestBasic", docStore, assetIds, kBatchSize, kRequestedSimultaneous, bulkOperation )
		:scan( function( totalProcessed, numberOfBatchesProcessed, bulkApplyOverlayResults )
			totalProcessed = totalProcessed + #bulkApplyOverlayResults
			numberOfBatchesProcessed = numberOfBatchesProcessed + 1
			return totalProcessed, numberOfBatchesProcessed
		end, 0, 0 )
		:takeLast( 1 )
	, #assetIds, kNumExpectedBatches )

	rxTest:expectEqual( kRequestedSimultaneous, maxSimultaneous )

	-- Check that the local only annotation is gone
	for _, assetId in ipairs( assetIds ) do

		rxTest:expectSingleValue( docStore:docValue( assetId )
			:pluck( "_localOnly", "batchTest" ), kBatchSize )

	end

end

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

return WFRxTestCase.wrapSuite( WFRxBatchedBulkOperationTest )
