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

 Copyright 2021 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.

 Created by IntelliJ IDEA.
 User: agk
 Date: 06/12/21
 Time: 4:35 PM

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

-- WF.core.diagnostic_log
local WFDiagnosticLog = require 'WFDiagnosticLog'

-- WF.core.utils
local WFLogger = require "WFLogger"
local WFRxRunUntilDone = require 'WFRxRunUntilDone'

local KSDate = require 'KSDate'
local WFDeviceInfo = require 'WFDeviceInfo'
local KSIdGenerator = require 'KSIdGenerator'
local KSTableUtils = require 'KSTableUtils'

-- WF.oz_client.utils
local OzCatalogUploadStatus = require 'OzCatalogUploadStatus'

-- WF.web.http_client
local KSJsonDecoder = require 'KSJsonDecoder'

local derefOpt = assert( KSTableUtils.derefOpt )

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

local logger = WFLogger( 'LrmVideoDevelopModel' )
:setLevel 'debug'

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

local Model = {}
local LrmVideoDevelopModel = {}
local recentDevelopSessions = {}

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

WFDiagnosticLog.addLogSectionFunc( function()

	logger:debugf('#recentDevelopSessions:%s', #recentDevelopSessions)

	if #recentDevelopSessions > 0 then

		return {

			name = "Recent Video Develop Sessions",
			id = 'LrmVideoDevelopModel',
			weight = 1201,

			body = {
				recentSessions = recentDevelopSessions,
			},

		}

	end

end )

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

local function closeSession( self )

	local exitStatus = 'close'

	if self.tsLogEntry.exitStatus ~= nil then

		exitStatus = self.tsLogEntry.exitStatus .. ' And ' .. exitStatus

	end

	self.tsLogEntry.exitStatus = exitStatus

	self.tsLogEntry.timeAtExit = KSDate.timeInIso8601Format()

end

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

local function applyDevelopChanges( self, revId, changes )

	logger:debugf('applyDevelopChanges, assetId: %s, revId: %s', self.assetId, revId)

	self.tsLogEntry.exitStatus = 'save'
	self.tsLogEntry.timeAtExit = KSDate.timeInIso8601Format()

	self.tsLogEntry.changes = {
		settings = changes or '(nil)',
	}

	self.tsLogEntry.saveStatus = {}

	changes = KSJsonDecoder.decodeWebSafeJson( changes )

	local deviceId = changes.deviceId

	if not deviceId then
		deviceId = WFDeviceInfo.uniqueDeviceId()
	end

	local userUpdated = KSDate.timeInIso8601Format( nil, false )

	local developAdjustments = derefOpt( changes, "adjustments" )

	local deviceNameWithId = string.format( '%s {%s}', WFDeviceInfo.deviceName(), deviceId )

	if type( developAdjustments ) == 'table' and next( developAdjustments ) then

		KSTableUtils.setNested( changes, userUpdated, 'adjustments', 'userUpdated' )
		KSTableUtils.setNested( changes, deviceNameWithId, 'adjustments', 'device' )
		
	end

	local developTemporal = derefOpt( changes, "temporal" )

	if type( developTemporal ) == 'table' and next( developTemporal )  then

		KSTableUtils.setNested( changes, userUpdated, 'temporal', 'userUpdated' )
		KSTableUtils.setNested( changes, deviceNameWithId, 'temporal', 'device' )
		
	end

	local newRevId = revId or KSIdGenerator.uuidInLowercaseHex()

	changes._replace = true

	local overlay = {

		_id = self.assetId,

		type = 'asset',

		develop = changes,

		userUpdated = userUpdated,

		_newRevId = newRevId,
	}

	self.tsLogEntry.overlay = overlay

	return self.catalog:docStore():applyOverlay( overlay )

		:map( function( response )

			logger:debugf("Got Response %s", response)

			return newRevId

		end )

		:tapOnCompleted( function()

			logger:debugf("tapOnCompleted")

		end )

		:tapOnError( function(err)

			logger:debugf("tapOnError: %s", err)

		end )
end

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

function Model:saveEditChanges( revId, changes )

	return {
		value = applyDevelopChanges(self, revId, changes)
				:call( WFRxRunUntilDone )
	}
end

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

local function getUrls( developInfo )

	local function getLink( links, type )

		return derefOpt( links, type, "href" )

	end

	local urls = {}

	local links = derefOpt( developInfo, "docValue", "_serverProvidedMetadata", "links")

	urls.proxy_360p = getLink( links, "/rels/proxy_type/360p" )
	urls.proxy_1080p = getLink( links, "/rels/proxy_type/1080p" )
	urls.proxy_360p_bt709 = getLink( links, "/rels/proxy_type/360p_bt709" )
	urls.proxy_1080p_bt709 = getLink( links, "/rels/proxy_type/1080p_bt709" )
	urls.proxy_hls = getLink( links, "/rels/proxy_type/hls" )

	urls.rendition_360p = getLink( links, "/rels/rendition_type/360p" )
	urls.rendition_720p = getLink( links, "/rels/rendition_type/720p" )
	urls.rendition_1080p = getLink( links, "/rels/rendition_type/1080p" )
	urls.rendition_2048 = getLink( links, "/rels/rendition_type/2048" )
	urls.rendition_fullsize = getLink( links, "/rels/rendition_type/fullsize" )
	urls.rendition_hls = getLink( links, "/rels/rendition_type/hls" )

	urls.main = getLink( links, "/rels/master" )

	return urls

end

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

function LrmVideoDevelopModel.makeModel( catalog, assetId )

	assert( catalog )
	assert( assetId )

	local tsLogEntry = {}

	local originalDocValue = catalog:docStore():ongoingDocValue( assetId )

	local prevDevelopInfo = {}

	local developSettings = originalDocValue

		:map( function( docValue )

			logger:debugf('got the document')

			local developInfo = {
				docValue = docValue
			}

			tsLogEntry.docValueAtEntry = developInfo

			recentDevelopSessions[ #recentDevelopSessions + 1 ] = tsLogEntry

			if #recentDevelopSessions > 10 then

				table.remove( recentDevelopSessions, 1 )

			end

			local settings = derefOpt( docValue, "develop") or {}

			developInfo.settings = settings

			return developInfo

		end )

		:map( function( developInfo )

			developInfo.urls = getUrls( developInfo )

			local localPath = derefOpt(  developInfo, "docValue", '_localOnly', 'originalFilePath' )

			if not localPath then
				localPath = derefOpt(  developInfo, "docValue", '_localOnly', 'latestOriginal', 'filePath' )
			end

			localPath = OzCatalogUploadStatus.checkAndCorrectLocalPath( localPath )
			local pixelAspectRatio = derefOpt( developInfo, "docValue", "video", "pixelAspectRatio") or { 1, 1 }
			local ratioValue = pixelAspectRatio[ 1 ] / (pixelAspectRatio[ 2 ] or 1.0)

			return {
				settings = developInfo.settings,
				urls = developInfo.urls,
				originalFilePath = localPath,
				originalHeight = derefOpt( developInfo, "docValue", "importSource", "originalHeight"),
				originalWidth = derefOpt( developInfo, "docValue", "importSource", "originalWidth"),
				transferFunction = derefOpt( developInfo, "docValue", "video", "transferFunction"),
				pixelAspectRatio = ratioValue
			}

		end )

		:filter( function( developInfo )

			if KSTableUtils.deepEquals( developInfo, prevDevelopInfo ) then

				return false

			end

			prevDevelopInfo = developInfo

			return true

		end)

		:map(function ( developInfo )

			logger:debugf('returning from lua')

			return developInfo

		end)

	catalog:getSyncClient():lockAssets( { assetId } ):call( WFRxRunUntilDone )

	return {
		models = Model,
		assetId = assetId,
		catalog = catalog,
		tsLogEntry = tsLogEntry,
		value = developSettings,

		close = function( self )

			catalog:getSyncClient():unlockAssets( { assetId } ):call( WFRxRunUntilDone )

			closeSession( self )

		end,
	}

end


return LrmVideoDevelopModel
