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

WFCatImportManifestStackAlbumsProcessor.lua

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

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

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

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

local WFConfiguration = require "WFConfiguration"

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

	-- WF.oz_client.managed_catalog.import
local WFCatImportManifestConstants = require 'WFCatImportManifestConstants'
local WFCatImportManifestProcessorBase = require 'WFCatImportManifestProcessorBase'

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

local function addStatus( manifestStatusDatabase, stackAlbums, status )
	
	local statusData = {}
	
	for i, stackAlbumId in ipairs( stackAlbums ) do
		statusData[ i ] = {
			local_id = stackAlbumId,
			status = status,
		}
	end
	
	return manifestStatusDatabase:writeData( 'addOrReplaceStackAlbumStatus', statusData )
		:ignoreElements()
end

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

local WFCatImportManifestStackAlbumsProcessor = {
	WFCatImportManifestProcessorBase,
	
}

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

function WFCatImportManifestStackAlbumsProcessor:__init()
	
	self._stageName = WFCatImportManifestConstants.stageNames.stackAlbums
	
	self._messageCodeCompleted = WFCatImportManifestConstants.messages.stackAlbumsProcessingComplete.code
	self._messageCodeErrorCount = WFCatImportManifestConstants.messages.stackAlbumsProcessingErrorCount.code
	self._messageCodeGenericError = WFCatImportManifestConstants.messages.stackAlbumsProcessingError.code
end

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

function WFCatImportManifestStackAlbumsProcessor:setup( catalog, manifestDatabase, manifestStatusDatabase, idCache, messageHandler )
	
	return self:WFCatImportManifestProcessorBase_setup( catalog, 
		manifestStatusDatabase, idCache, messageHandler, 'selectStackAlbumStatus' )

end

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

function WFCatImportManifestStackAlbumsProcessor:process( ... )

	if WFConfiguration.Manifest.disableStacks then
		local retSubject = ReplaySubject( 1 )
		retSubject:onNext( true )
		retSubject:onCompleted()
		return retSubject
	end
	
	return self:WFCatImportManifestProcessorBase_process( ... )
end

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

function WFCatImportManifestStackAlbumsProcessor:processImpObservable( catalog, profileCatalog, wfCatSynchronizer, 
		manifestDatabase, manifestStatusDatabase, idCache, messageHandler )
	
	return self:_maybeSetCount( manifestDatabase, 'countStackAlbums' )
	
		:flatMap( function()
		
			return manifestDatabase:readData( 'selectStackAlbums' )
			
		end )

		:flatMap( function( rows )
			
			-- This will get executed once per read batch
			
			local albumsStackIds = {}
			local albumStackAlbumLocalIds = {}
			local skippedEntries = {}
			
			for i, row in ipairs( rows ) do
				
				if self:_isAlreadyProcessed( row.local_id ) then
					
					self:_updateAlreadyProcessed( messageHandler, 1 )
				
				else
				
					local albumOzId = idCache:getOzIdForLocalId( WFCatImportManifestConstants.idCacheSets.albums, row.album )
					local stackOzId = idCache:getOzIdForLocalId( WFCatImportManifestConstants.idCacheSets.stacks, row.stack )
					
					if not albumOzId then
					
						self:_updateError( messageHandler, 1 )
						self:_sendMessage(
							messageHandler,
							WFCatImportManifestConstants.messages.stackAlbumsProcessingMissingAlbumError.code,
							{ { row.local_id, row.stack, row.album } }
						)
						
						skippedEntries[ #skippedEntries + 1 ] = row.local_id
						
					elseif not stackOzId then
					
						self:_updateError( messageHandler, 1 )
						self:_sendMessage(
							messageHandler,
							WFCatImportManifestConstants.messages.stackAlbumsProcessingMissingStackError.code,
							{ { row.local_id, row.stack, row.album } }
						)
						
						skippedEntries[ #skippedEntries + 1 ] = row.local_id
						
					else
						albumsStackIds[ albumOzId ] = albumsStackIds[ albumOzId ] or {}
						table.insert( albumsStackIds[ albumOzId ], stackOzId  )
						
						albumStackAlbumLocalIds[ albumOzId ] = albumStackAlbumLocalIds[ albumOzId ] or {}
						table.insert( albumStackAlbumLocalIds[ albumOzId ], row.local_id  )
					end
				
				end
			end
			
			local updateStatusObservable
			if #skippedEntries > 0 then
				-- Record status value
				updateStatusObservable = addStatus( manifestStatusDatabase, skippedEntries, WFCatImportManifestConstants.status.failure )
			else
				updateStatusObservable = Observable.empty()
			end
			
			return updateStatusObservable
				:defaultIfEmpty( nil )
				:map( function()
					
					return albumsStackIds, albumStackAlbumLocalIds
				end )
			
		end )
		
		:flatMap( function( albumsStackIds, stackAlbumLocalIds )
			
			return Observable.create( function( observer )
				for album, stacks in pairs( albumsStackIds ) do
					observer:onNext( album, stacks, stackAlbumLocalIds[ album ] )
				end
				
				observer:onCompleted()
			end )
		end )
		
		:flatMap( function( albumOzId, stackOzIds, stackAlbumLocalIds )
			
			return WFCatAlbums.addAssetsToAlbum( catalog, albumOzId, stackOzIds )
					:ignoreElements()
					:defaultIfEmpty( nil )
					:flatMap( function()
					
						self:_updateSuccess( messageHandler, #stackOzIds )
						
						return addStatus( manifestStatusDatabase, stackAlbumLocalIds, WFCatImportManifestConstants.status.success )
							
					end )
					
					:catch( function( err )
						self:_updateError( messageHandler, #stackOzIds )
						self:_sendMessage(
							messageHandler,
							WFCatImportManifestConstants.messages.stackAlbumsProcessingError.code,
							{ err }
						)
						
						return addStatus( manifestStatusDatabase, stackAlbumLocalIds, WFCatImportManifestConstants.status.failure )
					end )
		end )
		:ignoreElements()
		:defaultIfEmpty( nil )
		:flatMap( function()
		
			local queryId = "countStackAlbumsStatus"
			local dataType = WFCatImportManifestConstants.dataTypes.stackAlbums
			return self:_sendSummary( messageHandler, manifestStatusDatabase, queryId, dataType )
			
		end )
		:ignoreElements()
			-- Adding summary step to the chain and then explicitely
			-- ignoring elements to denote that we are not interested
			-- in the return values.
end

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

return Rx.Class 'WFCatImportManifestStackAlbumsProcessor'( WFCatImportManifestStackAlbumsProcessor )
