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

WFCatExportHelper.lua

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

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

----------------------------------------------------------------------------]]--
	-- RxLua
local Rx = require 'Rx'
local Observable = Rx.Observable

	-- WF.core.logging
local WFLogger = require 'WFLogger'

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

	-- WF.oz_client.managed_catalog.file_management
local WFCatFileSpec = require "WFCatFileSpec"

	-- WF.oz_client.managedCatalog.metadata
local WFCatExportMetadata = require 'WFCatExportMetadata'

	-- lightroomcc
local NmbAcr = require 'NmbAcr'

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

local logger = WFLogger 'WFCatExportMetadataHelper'
	--:setLevel( 'DEBUG' )

local derefOpt = assert( KSTableUtils.derefOpt )

local WFCrContext = NmbAcr.WFCrContext

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

local function getXmpDevelopPath( exportPixelProviderTask, assetId )
	
	local xmpDevelopStream = exportPixelProviderTask:getXmpDevelop( assetId )

	return xmpDevelopStream
			:take( 1 )
			:map( function( success, xmpDevelopFilePath )

				if not success or not xmpDevelopFilePath then
					
					local errMsg = xmpDevelopFilePath or 'PixelProvider returned nil'
					logger:errorf( "Failed to fetch xmp_develop for assetId '%s' because: %s.", 
						assetId, errMsg  )

					error( 'xmp_develop_unavailable' )
					
				end
				
				return xmpDevelopFilePath
			end )

end

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

local function getXmpCameraRaw( exportPixelProviderTask, docValue, optDevSettingsOverride )
	
	local result
	
	local xmpCameraRawDoc = derefOpt( docValue, "develop", "xmpCameraRaw" )
	
	result = Observable.just(  xmpCameraRawDoc or '' )
	
	if optDevSettingsOverride and optDevSettingsOverride.xmp then
		
		-- we've been given overriding develop settings as xmp, use it instead of
		-- what we get from the docValue
		result = Observable.just( optDevSettingsOverride.xmp )
	
	elseif type( xmpCameraRawDoc ) == 'table' then 
			
		result = getXmpDevelopPath( exportPixelProviderTask, docValue._localId )
			:flatMap( function( xmpDevelopPath )
			
				return WFAsyncFileUtils.readFile( xmpDevelopPath )
			
			end )
			:map( function( xmpDevelop )
			
				local xmpDevelopStr = tostring( xmpDevelop )
				xmpDevelop:close()
				
				return xmpDevelopStr
				
			end )
		
	end
	
	return result

end

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

local function getXmpSidecarFromPixelProvider( exportPixelProviderTask, assetId )

	-- Tell pixel provider to download the xmp sidecar returning
	-- the path it is downloaded to if one exists.

	return exportPixelProviderTask:getXmpSidecar( assetId )
		:take( 1 )
		:map( function( success, xmpSidecarFilePath )

			if not success then

				local errMsg = xmpSidecarFilePath
				logger:warnf( "Failed to fetch xmp_sidecar for assetId '%s' because: %s.",
					assetId, errMsg  )

				-- NMB-4613: Continue with the metadata that we have
				-- if we are not able to download the sidecar.
				--error( 'xmp_sidecar_unavailable' )
				return nil
			end

			return xmpSidecarFilePath

		end )

end

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

local function getXmpSidecar( exportPixelProviderTask, docValue )

	local result

	local xmpSidecarPath = WFCatFileSpec.getXmpSidecarPathFromDocValue( docValue )

	if xmpSidecarPath then

		-- already have the file locally just return the path

		result = Observable.just( xmpSidecarPath )

	else

		local hasXmpSidecar = WFCatFileSpec.getXmpSidecarExistsFromDocValue( docValue )

		if hasXmpSidecar == false then

			-- No sidecar was used so just return nil
			return Observable.just( nil )

		else -- hasXmpSidecar == true or hasXmpSidecar == nil

			-- hasXmpSidecar == nil if we don't know if there is a sidecar or not
			-- hasXmpSidecar == true if we know there is one but don't have the file locally

			result = getXmpSidecarFromPixelProvider( exportPixelProviderTask, docValue._localId )

		end

	end

	result = result
		:flatMap( function( filePath )

			if filePath == nil then
				-- xmp on oz is not from a sidcar just return nil
				return Observable.just( nil )
			end

			return WFAsyncFileUtils.readFile( filePath )
				:map( function( xmpSidecarData )

					local xmpSidecarStr = tostring( xmpSidecarData )
					xmpSidecarData:close()

					return xmpSidecarStr

				end )

		end )

	return result

end

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

local WFCatExportHelper = {}

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

function WFCatExportHelper.getXmpForExport( exportPixelProviderTask, 
	negativePath, docValue, userId, optDevSettingsOverride, removeFaceInfo )

	return Observable.combineLatest( function( xmpSidecarData, xmpCameraRaw )

			local success, renderContext = pcall( WFCrContext, negativePath )

			if not success then
				logger:warnf( 'WFCrContent init failed for %s', tostring( negativePath ) )
				return Observable.throw( 'invalid_original' )
			end

			return renderContext
				:mergeMetadata( xmpCameraRaw, xmpSidecarData )
				:catch( function()
					return Observable.throw( 'unsupported_file' )
				end)
				:map( function( info )
					assert( info and info.metadata, "Merge metadata failed" )
					local metadata = WFCatExportMetadata.createCompleteXmp( docValue, userId, info.metadata, true, removeFaceInfo )
					return metadata
				end )

		end,
		getXmpSidecar( exportPixelProviderTask, docValue ),
		getXmpCameraRaw( exportPixelProviderTask, docValue, optDevSettingsOverride )
	)

	:switch()

end

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

function WFCatExportHelper.getProxyPath( exportPixelProviderTask, assetId )
	
	local proxyStream = exportPixelProviderTask:getProxy( assetId )
	
	return proxyStream
			:take( 1 )
			:map( function( success, proxyFilePath )

				if not success or not proxyFilePath then

					local errMsg = proxyFilePath or 'PixelProvider returned nil'
					logger:warnf( "Failed to fetch proxy for assetId '%s' because: %s", 
						assetId, errMsg  )
					error( 'proxy_unavailable' )

				end

				return proxyFilePath
			end)

end
--============================================================================--

return WFCatExportHelper
