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

DesktopCommonIndexDefinitions.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2023 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.utils
local KSTableUtils = require 'KSTableUtils'
local KSStringUtils = require 'KSStringUtils'
local WFArguments = require 'WFArguments'

	-- WF.oz_client.managed_catalog
local WFCatIndexUtils = require 'WFCatIndexUtils'
local WFCatFileSpec = require 'WFCatFileSpec'

	-- WF.sqlite.index_store
local WFRxIndexStoreSchema = require 'WFRxIndexStoreSchema'

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

local derefOpt = KSTableUtils.derefOpt
local isValidDisplayableAssetDocument = WFCatIndexUtils.isValidDisplayableAssetDocument
local getDuration = assert( WFCatIndexUtils.getDuration )
local getOrientationWidthAndHeight = assert( WFCatIndexUtils.getOrientationWidthAndHeight )

local check = assert( WFArguments.check )

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

local function getRating( docValue )

	local ratings = derefOpt( docValue, 'ratings' )
	
	if ratings then

		-- Due to legacy issues, ratings are keyed by user id. We can now assume
		-- only one user (the current user) is able to rate a photo.

		local _, v = next( ratings )

		if v then
			return v.rating or 0
		end
	end
	
	return 0
end

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

local flagNameToInteger = {
	reject = -1,
	unflagged = 0,
	pick = 1,
}

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

local function getFlag( docValue )

	local reviews = derefOpt( docValue, 'reviews' )
	
	if reviews then

		-- Due to legacy issues, flags are keyed by user id. We can now assume
		-- only one user (the current user) is able to flag a photo.

		local _, v = next( reviews )

		if v then
			local flagName = v.flag
			
			if flagName then
				return flagNameToInteger[ flagName ] or 0
			end

		end
	end
	
	return 0
end

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

local DesktopCommonIndexDefinitions = {}

function DesktopCommonIndexDefinitions.generateIndexSchema( indexStoreSchema )
	
	check( 'WFRxIndexStoreSchema' )

	-- table assets
	
	indexStoreSchema:addTable {
		sql = [[CREATE TABLE assets( 
				width INTEGER, 
				height INTEGER, 
				orientation INTEGER, 
				captureDate, 
				filename, 
				filenameLC, 
				assetId, 
				subtype, 
				rating INTEGER, 
				flag INTEGER, 
				duration INTEGER, 
				isMedia,
				isMarkedForOffline,
				spaceId,
				importedByUser,
				serverCreated )]],
	
		relevantTypeSubtypeTuples = {
			{ 'asset', 'image' },
			{ 'asset', 'video' },
			{ 'asset', 'stack' },
		},
		
		map = function( docValue, emit )
			
			local isDisplayable, displayableDocValue = isValidDisplayableAssetDocument( docValue )
			
			if isDisplayable then

				local subtype = docValue.subtype
			
				local isMedia = subtype == 'image' or subtype == 'video'

				local orientation, width, height = getOrientationWidthAndHeight( displayableDocValue )

				local filename = derefOpt( displayableDocValue, 'importSource', 'fileName' )
				
				local filenameLC = ""
				
				if filename and type( filename ) == "string" then
				
					filenameLC = KSStringUtils.lower( filename )
					filenameLC = KSStringUtils.trim( filenameLC )
					
				end
				
				local captureDate = derefOpt( displayableDocValue, 'captureDate' )

				local rating = getRating( displayableDocValue )

				local flag = getFlag( displayableDocValue )

				local duration = getDuration( displayableDocValue )

				isMedia = isMedia and 1 or 0

				local isMarkedForOffline = WFCatFileSpec.getMarkedForOfflineUseFromDocValue( docValue ) and 1 or 0
				
				local spaceId = docValue._spaceId
				
				local importedByUser = derefOpt( docValue, '_serverProvidedMetadata', 'importedByUser', 'id' ) 
				
				local serverCreated = derefOpt( docValue, '_serverProvidedMetadata', 'created' )
				
				if width and height and captureDate then

					emit( width, height, orientation, captureDate, filename, filenameLC, docValue._id, 
							subtype, rating, flag, duration, isMedia, isMarkedForOffline, spaceId, 
							importedByUser, serverCreated )

				end

			end

		end,

		useLocalId = true,
		hasOneRowPerDocument = true,

	}

	indexStoreSchema:addIndex [[CREATE INDEX assets_assetIddocId ON assets( assetId, docId )]]

	indexStoreSchema:addIndex [[CREATE INDEX assets_assetIdsubtype ON assets( assetId, subtype )]]

	indexStoreSchema:addIndex [[CREATE INDEX assets_subtype ON assets( subtype )]]
	
	indexStoreSchema:addIndex [[CREATE INDEX assets_captureDatefilename ON assets( captureDate, filenameLC COLLATE i18n_collate )]]
	
	indexStoreSchema:addIndex [[CREATE INDEX assets_assetIdIsMediaCaptureDateFileNameLCServerCreated ON assets( assetId, isMedia, captureDate, fileNameLC, serverCreated )]]

	indexStoreSchema:addIndex [[CREATE INDEX assets_isMarkedForOffline ON assets( isMarkedForOffline, assetId )]]
	
	-- table project_albums
	
	-- The base albums and album_asset_v2 tables can still be found in WFCatSearchByAlbum. Moving it
	-- here causes the table to be built unnecessarily so, for now, we leave those over there until
	-- they're being rebuilt for other reasons
	
	--------------------------------------------------------------------------------

	indexStoreSchema:addTable {
		
		sql = [[CREATE TABLE project_albums( 
					albumId,
					name, 
					updateTimestamp, 
					sourceAlbumId,
					serviceId,
					pendingPublish,
					syncStatus,
					notifyConnect,
					coverId,
					assetSortOrder)]],

		useLocalId = true,
		
		hasOneRowPerDocument = true,
		
		relevantTypeSubtypeTuples = {
			{ 'album', 'project' },
		},
		
		map = function( docValue, emit )

			-- Don't emit index store records for album subtypes we don't understand since the UI may not show
			-- things correctly. The basic album subtype is of type 'collection' which is the classic type of album. 
			-- The full list of subtypes can be found here http://apidocs.adbecrsl.com/v2/data-model/album/index.html
			-- Since the different subtypes tend to represent different concepts they may end up in separate tables
			-- entirely.
			if docValue and docValue.type == 'album' 
					and docValue.subtype == 'project'
					and not docValue._deleted then

				local publishInfo = derefOpt( docValue, 'publishInfo' )
				
				local deletedOnThirdPartyService = derefOpt( publishInfo, 'deleted' )
				if deletedOnThirdPartyService then
					-- if the connection was deleted via the third party service, then it's marked in Oz
					-- with a 'deleted' flag under publishInfo but the actual document still exists on Oz
					-- we should ignore these
					return
				end
				
				local notifyConnect = derefOpt( docValue, '_localOnly', 'publishNotifications') and 1 or 0
				local editUrl = derefOpt( docValue, '_localOnly', 'publishNotifications', 'editUrl' )
				local pendingPublish = editUrl == 'pending' and 1 or 0
				
				local name = docValue.name
				
				local albumId = docValue._id
				local localTimeStamp = derefOpt( docValue, 'userUpdated' ) 
				local ozTimeStamp = derefOpt( docValue, '_serverProvidedMetadata', 'updated' )
				local updateTimestamp = localTimeStamp or ozTimeStamp
				local sourceAlbumId = derefOpt( docValue, 'sourceAlbum', 'id' ) 
				local serviceId = derefOpt( docValue, 'serviceId' )
					or derefOpt( publishInfo, 'serviceId' )
				local coverId = derefOpt( docValue, 'cover', 'id' )
	
				-- low resolution sync status - if the local stamp < oz time stamp and not pending Publish
				local syncStatus = 'syncPending'
				if not localTimeStamp then
					-- early project_album records may be missing a userUpdated field. Consider these synced
					-- even if we can't guarantee it.
					syncStatus = 'synced'
				elseif ozTimeStamp and ozTimeStamp >= localTimeStamp then
					syncStatus = 'synced'
				end
				
				local assetSortOrder = derefOpt( docValue, 'assetSortOrder' )
				
				if docValue._spaceId then
				
					-- For space-feed documents, the asset sort order can be changed by the contributor/viewer
					-- but it is a local-only change; they cannot overwrite the album order set by the album owner.
					
					assetSortOrder = derefOpt( docValue, '_localOnly', 'universal', 'assetSortOrder' ) or assetSortOrder
					
				end
				
				if albumId and name then
		
					emit( albumId, name, updateTimestamp, sourceAlbumId, serviceId, pendingPublish, syncStatus, notifyConnect, coverId, assetSortOrder )
							
				end

			end

		end,
		
	}
	
end

return DesktopCommonIndexDefinitions
	