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

LrClassicBinaryDownloader.lua

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

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

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


local Rx = require 'Rx'
local Observable = Rx.Observable
local WFCatPixelFileCacheSave = require 'WFCatPixelFileCacheSave'
local WFBinaryRequester = require "WFBinaryRequester"
local WFCatBinaryDownloader = require "WFCatBinaryDownloader"
local WFCatAssetAux = require "WFCatAssetAux"
local WFFileUtils = require 'WFFileUtils'
local WFArguments = require 'WFArguments'
local WFTableMerge = require 'WFTableMerge'

local KSData = require "KSData"
local WFCrypto = require 'WFCrypto'

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

local check = assert( WFArguments.check )
local httpRequestPriority = 2
local auxBasePath

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

local logger = require 'WFLogger'( 'LrClassicBinaryDownloader' )

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

local LrClassicBinaryDownloader  = {
	_wfCatalog = false,
		-- (WFCatalog)
		
	_binaryDownloader = false,
		-- (WFCatBinaryDownloader),
		
	_pixelFileCacheSave=false,
		-- (WFCatPixelFileCacheSave),
		
}

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

function LrClassicBinaryDownloader:__init( wfCatalog )

	check( 'LrClassicBinaryDownloader', 'WFCatalog' )

	self._wfCatalog = wfCatalog
	
	self._binaryDownloader = WFCatBinaryDownloader( wfCatalog )
	
	self._pixelFileCacheSave = WFCatPixelFileCacheSave( "ClassicPixelFileCacheSaver",  20 )

end

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

function LrClassicBinaryDownloader:close()

	check( 'LrClassicBinaryDownloader' )

	if self._binaryDownloader then 
		self._binaryDownloader:close()
		self._binaryDownloader = nil
	end

	if self._pixelFileCacheSave then
		self._pixelFileCacheSave:close()
		self._pixelFileCacheSave = nil
	end
end

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

function LrClassicBinaryDownloader:updateLocalOnlyForDoc( docId, filePath, ozBinaryType )
	
	return self._wfCatalog:docStore():docValue( docId )
	:flatMap( function( docValue )
		
		--WF-2455: In LrC after applying xmp we delete the file and we have to update the localOnly 
		-- in next call hence adding this check to skip adding to localonly section
		if docValue._empty or docValue.type ~= 'asset' or ozBinaryType == "xmp_develop" then
			return Observable.just( nil )
		end
		
		local overlay = {
			_id = docId
		}
		
		local volumeGuid = WFFileUtils.getVolumeGuidForPath( filePath )
		local relativePath = WFFileUtils.removeVolumeFromPath( filePath )

		local fileAttributes = WFFileUtils.fileAttributes( filePath )
		local fileSize = fileAttributes and fileAttributes.fileSize or 0
		
		return WFCrypto.asyncDigestFile( filePath, 'SHA256' )
			
			:flatMap( function( fileSha256 )
			
				if ozBinaryType == "original" then
				
					overlay._localOnly = {
						files = {
							original = {
								master = {
									relativePath = relativePath,
									volumeGuid = volumeGuid,
									sha256 = fileSha256,
									size = fileSize
								}
							}
						}
					}
					
				elseif ozBinaryType == "proxy" then
				
					overlay._localOnly = {
						files = {
							proxy = {
								[ "2560" ] = {
									relativePath = relativePath,
									volumeGuid = volumeGuid,
									sha256 = fileSha256,
									size = fileSize
								}
							}
						}
					}
					
				elseif ozBinaryType == "xmp_develop" then
				
					overlay._localOnly = { 
						files = {
							xmp_develop = {
								path = filePath,
								sha256 = fileSha256,
							}
						},
						sourceXmpDevelopLink = { _delete = true } -- WF-1323: settings changes should remove sourceXmpDevelopLink as its no longer valid
					}
					
				end
				
				return self._wfCatalog:docStore():applyOverlay( overlay )
				
			end )

	end )
	
end

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

--[[!
	\Downloads the binary and save it to file path provided.
	
	\docId<string> docId of the asset
	
	\filePath<string> filepath where binary is going to be saved
	
	\ozBinaryType<string> asset or xmp_develop
	
	\ozBinarySize<string> proxy or original
	
	\return <code>Observable<></code> An Observable object whose value is the _pixelFileCacheSave

 ]]--
 
function LrClassicBinaryDownloader:downloadOneBinaryToFilePath( docId, filePath, ozBinaryType, ozBinarySize )

	local binaryRequester = WFBinaryRequester( self._binaryDownloader )

	binaryRequester:requestBinary( docId, ozBinaryType, ozBinarySize, httpRequestPriority )

	local binaryRequestStream = binaryRequester:getBinaryRequestStream()
	
	return binaryRequestStream
		:flatMap( function( okay, maybeKSDataOrError, revId, ozAssetId,
						ozBinaryType, ozBinarySizeName, addlInfo )
						
			if not okay then
			
				logger:errorf( "error in binaryRequestStreamHandler for %s: %s",  docId, ozBinaryType )
				Observable.throw( maybeKSDataOrError )
				
			end
			
			local binaryBlob = KSData.isData( maybeKSDataOrError ) and maybeKSDataOrError or nil
			
			if not binaryBlob then 
				return Observable.throw( "Not a blob data for %s" , docId )
			end
			
			return Observable.create( function( observer )
				self._pixelFileCacheSave 
					:savePixels( filePath, binaryBlob )
					:subscribe( function()
						
							logger:warnf( "Unexpected onNext event when saving %s blob to %s save for localAssetId %s","original", filePath, docId )
							
						end,

						function( errStr )
						
							observer:onError( errStr )
							
						end,

						function()
						
							observer:onNext( docId )
							observer:onCompleted()
							
							self:updateLocalOnlyForDoc( docId, filePath, ozBinaryType )
							:subscribe()
					
					end)
				end )
				
		end)
end

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

--[[!
	\Downloads the aux of docId provided.
	
	\docId<string> docId of the asset
	
	\optFnAuxFileExistenceCheck<string> function passed from client which tells
	if aux is present with client or not
	
	\return <code>Observable<></code> An Observable object 

 ]]--

function LrClassicBinaryDownloader:downloadAux( docId )
	return self._wfCatalog:docStore():docValue( docId )
		:flatMap( function( docValue )
			return  WFCatAssetAux.ensureAuxFilesExistLocally( self._wfCatalog, docValue )
		end )
end

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

--[[!
	\retur the auxs of docId provided with filePaths.
	
	\docId<string> docId of the asset
	
	
	\return <code>Observable<></code> filePath and detail of all auxs of an asset

 ]]--

function LrClassicBinaryDownloader:auxDownloadedPath( docId )
	auxBasePath = auxBasePath or WFCatAssetAux.getBasePath( self._wfCatalog )
	return self._wfCatalog:docStore():docValue( docId )
		:map( function( docValue )
		
			local digestsByAuxId = WFTableMerge.applyOverlay(
				WFCatAssetAux.extractDevelopAuxDigestsFromDocValue( docValue ),
				WFCatAssetAux.extractC2paAuxDigestFromDocValue( docValue )
			)

			local absoluteFilePaths = {}
			
			for _, digest in pairs(	digestsByAuxId ) do
				absoluteFilePaths[digest] = WFCatAssetAux.calculatePathUsingDigest( auxBasePath, digest )
			end
			
			return absoluteFilePaths
			
		end )
end

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

return Rx.Class( 'LrClassicBinaryDownloader', LrClassicBinaryDownloader ) 
