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

WFCatNotificationTest.lua

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

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

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

	-- WF.core.self_test
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.core.utils
local KSDate = require 'KSDate'
local KSIdGenerator = require 'KSIdGenerator'
local KSJsonEncoder = require 'KSJsonEncoder'
local WFRxDatabase = require 'WFRxDatabase'

	-- notification
local WFCatNotification = require 'WFCatNotification'

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

local WFCatNotificationTest = {}

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

local TEST_TIMEOUT = 4

local function notificationDbSetUp( rxTest )

	local db = WFRxDatabase( ':memory:' , 'LrRxNotificationDbDefinitions.lua', '1.1' )
	
	rxTest:finally( function()
		db:close()
	end )
	
	return db

end

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

local function addOneCommentNotification( rxTest, notificationDb, optDate )

	optDate = optDate or KSDate.timeInIso8601Format()

	local notificationId = KSIdGenerator.uuidInLowercaseHex()
	local subtype = "comment"
	local time = optDate
	local payload = {
		type = "com.adobe.lightroom",
		subtype = "comment",
		targetDestination = "asset",
		primaryImage = "asset",
		secondaryImage = "person",
		text = "{person/full_name} commented on 1 photo",
		subtext = "{full_period_phrase} in {album/name}",
		asset = {
			id = "assetId",
			subtype = "image",
			thumbnail_url = "asset_thumbnail_url"
		},
		album = {
			id = "albumId",
			name = "albumName"
		},
		comment = {
			id = "commentId",
			body = "commentBody"
		}
	}
	
	local payloadJsonString = KSJsonEncoder.prettyPrint( payload )
	
	local newRows = {
		{ notificationId, subtype, time, false, payloadJsonString, false, true }
	}

	rxTest:waitFor( notificationDb:bulkInsert( "notifications", newRows ) )
	
	rxTest:observe( notificationDb:query( {
			sql = "SELECT notificationId FROM notifications WHERE subtype = ?", "comment"
		} ) )
		:expectDataWithinTime( 2, {{ notificationId }} )
		
	payload.notificationId = notificationId
	payload.subtype = subtype
	payload.time = time
	payload.read = false
	payload.visited = false
	
	return payload
	
end

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

local function addOneFavoriteNotification( rxTest, notificationDb, optDate )

	optDate = optDate or KSDate.timeInIso8601Format()

	local notificationId = KSIdGenerator.uuidInLowercaseHex()
	local subtype = "favorite"
	local time = optDate
	local payload = {
		type = "com.adobe.lightroom",
		subtype = "favorite",
		targetDestination = "asset",
		primaryImage = "asset",
		secondaryImage = "person",
		text = "{person/full_name} liked 1 photo",
		subtext = "{full_period_phrase} in {album/name}",
		asset = {
			id = "assetId",
			subtype = "image",
			thumbnail_url = "asset_thumbnail_url"
		},
		album = {
			id = "albumId",
			name = "albumName"
		},
		person = {
			id = "personId",
			full_name = "person_full_name",
			thumbnail_url = "person_thumbnail_url"
		},
		favorite = {
			id = "favoriteId"
		}
	}
	
	local payloadJsonString = KSJsonEncoder.prettyPrint( payload )

	local newRows = {
		{ notificationId, subtype, time, false, payloadJsonString, false, true }
	}

	rxTest:waitFor( notificationDb:bulkInsert( "notifications", newRows ) )
	
	rxTest:observe( notificationDb:query( {
			sql = "SELECT notificationId FROM notifications WHERE subtype = ?", "favorite"
		} ) )
		:expectDataWithinTime( 2, {{ notificationId }} )
	
	payload.notificationId = notificationId
	payload.subtype = subtype
	payload.time = time
	payload.read = false
	payload.visited = false
	
	return payload
	
end

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

local function addOneAggregatedAssetAddedNotification( rxTest, notificationDb, optDate )

	optDate = optDate or KSDate.timeInIso8601Format()

	local notificationId = KSIdGenerator.uuidInLowercaseHex()
	local subtype = "favorite"
	local time = optDate
	local payload = {

		targetDestination =  "album",
		secondaryImage = "person",
		-- secondaryImageUI is deliberately omitted
		primaryImage = "asset",
		primaryImageUI = "asset-stack",
		text =  "{person/full_name} added {unique_count} photos.",
		subtext = "{full_period_phrase} in {album/name}",

		unique_count = 2,
		unique_count_field = "asset",
		aggregated_notifications = {
			{
				type = "com.adobe.lightroom",
				subtype = "asset-added",
				catalog_id = "dc513417b7374775a2c071b679c6959b",
				space_id = "b44deae353c44887bbc1153b6317204f",
				asset = {
					id = "69c13b869a1f4886b07073b06fbe0d15",
					thumbnail_url = "https://photos-stage.adobe.io/v2/catalogs/dc513417b7374775a2c071b679c6959b/assets/69c13b869a1f4886b07073b06fbe0d15/revisions/03b55c6818014b9c88e77696e07f362b/renditions/ae0c2797803317e96de8cb15fdcb5762",
					subtype = "image"
				},
				album = {
					id = "79c2d76d0be643b49bda50af3622a1ea",
					name = "Sammlung Falckenberg"
				},
				person = {
					id = "b2d1cad69bf1f9c840e3b90cf6dfe7b5",
					full_name = "Kasper Koenig",
					thumbnail_url = "https://photos-stage.adobe.io/v2/avatars/b2d1cad69bf1f9c840e3b90cf6dfe7b5/20201119174542/small"
				}
			},
			{
				type = "com.adobe.lightroom",
				subtype = "asset-added",
				catalog_id = "dc513417b7374775a2c071b679c6959b",
				space_id = "b44deae353c44887bbc1153b6317204f",
				asset = {
					id = "46ab60c9228c4c058bb00703218968a5",
					thumbnail_url = "https://photos-stage.adobe.io/v2/catalogs/dc513417b7374775a2c071b679c6959b/assets/46ab60c9228c4c058bb00703218968a5/revisions/f0dba2930c4e4048bfb0ccb6b8980960/renditions/7aa882caf3451143111589ce15b958be",
					subtype = "image"
				},
				album = {
					id = "79c2d76d0be643b49bda50af3622a1ea",
					name = "Sammlung Falckenberg"
				},
				person = {
					id = "b2d1cad69bf1f9c840e3b90cf6dfe7b5",
					full_name = "Kasper Koenig",
					thumbnail_url = "https://photos-stage.adobe.io/v2/avatars/b2d1cad69bf1f9c840e3b90cf6dfe7b5/20201119174542/small"
				}
			}
		},
		
		type = "com.adobe.lightroom",
		subtype = "asset-added",
		catalog_id = "dc513417b7374775a2c071b679c6959b",
		space_id = "b44deae353c44887bbc1153b6317204f",
		asset = {
			id = "69c13b869a1f4886b07073b06fbe0d15",
			thumbnail_url = "https://photos-stage.adobe.io/v2/catalogs/dc513417b7374775a2c071b679c6959b/assets/69c13b869a1f4886b07073b06fbe0d15/revisions/03b55c6818014b9c88e77696e07f362b/renditions/ae0c2797803317e96de8cb15fdcb5762",
			subtype = "image"
		},
		album = {
			id = "79c2d76d0be643b49bda50af3622a1ea",
			name = "Sammlung Falckenberg"
		},
		person = {
			id = "b2d1cad69bf1f9c840e3b90cf6dfe7b5",
			full_name = "Kasper Koenig",
			thumbnail_url = "https://photos-stage.adobe.io/v2/avatars/b2d1cad69bf1f9c840e3b90cf6dfe7b5/20201119174542/small"
		}
	}
	
	local payloadJsonString = KSJsonEncoder.prettyPrint( payload )

	local newRows = {
		{ notificationId, subtype, time, false, payloadJsonString, false, true }
	}

	rxTest:waitFor( notificationDb:bulkInsert( "notifications", newRows ) )
	
	rxTest:observe( notificationDb:query( {
			sql = "SELECT notificationId FROM notifications WHERE subtype = ?", "favorite"
		} ) )
		:expectDataWithinTime( 2, {{ notificationId }} )
	
	payload.notificationId = notificationId
	payload.subtype = subtype
	payload.time = time
	payload.read = false
	payload.visited = false
	
	return payload
	
end

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

local function stripWobblyBits( notifications )

	local result = {}

	for i = 1, #notifications do
				
		local notification = notifications[ i ]
	
		notification.time = "time"
		
	end
	
	return result

end
--------------------------------------------------------------------------------

function WFCatNotificationTest.rxTestNotificationList( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local notificationDb = notificationDbSetUp( rxTest )

	local notificationObs = rxTest:observe( WFCatNotification.notificationList( notificationDb )
		:map( stripWobblyBits ) )

	rxTest:finally( function()
		notificationObs:dispose()
	end )

	notificationObs:expectData( {} )
	
	local commentNotification = WFCatNotification.DEBUG_synthesizeFieldsAndReverse(
		addOneCommentNotification( rxTest, notificationDb ) )
	
	local favoriteNotification = WFCatNotification.DEBUG_synthesizeFieldsAndReverse(
		addOneFavoriteNotification( rxTest, notificationDb ) )

	-- most recent on top
	notificationObs:expectDataWithinTime( 2, stripWobblyBits {
			commentNotification,
			favoriteNotification
		} )
	
end

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

function WFCatNotificationTest.rxTestNotificationListSynthesizedFields( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local notificationDb = notificationDbSetUp( rxTest )
	local notificationObs = rxTest:observe( WFCatNotification.notificationList( notificationDb ) )
	rxTest:finally( function()
		notificationObs:dispose()
	end )
	
	notificationObs:expectData( {} )

	local aggregatedAssetAdded = addOneAggregatedAssetAddedNotification( rxTest, notificationDb )

	-- synthesize the fields manually
	aggregatedAssetAdded[ 'asset-stack' ] = {
		{
			id = "46ab60c9228c4c058bb00703218968a5",
			thumbnail_url = "https://photos-stage.adobe.io/v2/catalogs/dc513417b7374775a2c071b679c6959b/assets/46ab60c9228c4c058bb00703218968a5/revisions/f0dba2930c4e4048bfb0ccb6b8980960/renditions/7aa882caf3451143111589ce15b958be",
		},
		{
			id = "69c13b869a1f4886b07073b06fbe0d15",
			thumbnail_url = "https://photos-stage.adobe.io/v2/catalogs/dc513417b7374775a2c071b679c6959b/assets/69c13b869a1f4886b07073b06fbe0d15/revisions/03b55c6818014b9c88e77696e07f362b/renditions/ae0c2797803317e96de8cb15fdcb5762"
		}
	}

	aggregatedAssetAdded.secondaryImageUI = aggregatedAssetAdded.secondaryImage
	
	-- and reverse the order
	aggregatedAssetAdded.aggregated_notifications[ 2 ], aggregatedAssetAdded.aggregated_notifications[ 1 ] =
		aggregatedAssetAdded.aggregated_notifications[ 1 ], aggregatedAssetAdded.aggregated_notifications[ 2 ]

	notificationObs:expectDataWithinTime( 2, {
		aggregatedAssetAdded
	} )

end

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

function WFCatNotificationTest.rxTestNotificationUnreadCount( rxTest )

	local notificationDb = notificationDbSetUp( rxTest )
	
	local notificationUnreadCountObs = rxTest:observe( WFCatNotification.notificationUnreadCount( notificationDb ) )
	rxTest:finally( function()
		notificationUnreadCountObs:dispose()
	end )
	
	notificationUnreadCountObs:expectData( 0 )
	
	addOneCommentNotification( rxTest, notificationDb )

	notificationUnreadCountObs:expectDataWithinTime( 2, 1 )
	
end

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

function WFCatNotificationTest.rxTestSetReadNotification( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local notificationDb = notificationDbSetUp( rxTest )

	local notificationObs = rxTest:observe( WFCatNotification.notificationList( notificationDb ) )
	rxTest:finally( function()
		notificationObs:dispose()
	end )

	notificationObs:expectData( {} )
	
	local commentNotification = WFCatNotification.DEBUG_synthesizeFieldsAndReverse( 
		addOneCommentNotification( rxTest, notificationDb ) )
	local commentNotificationId = commentNotification.notificationId
	
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )
		
	rxTest:expectSingleValue( WFCatNotification.setReadNotification( notificationDb, { commentNotificationId } ), 1 )
	
	commentNotification.read = true
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )

	-- set to unread
	rxTest:expectSingleValue( WFCatNotification.setReadNotification( notificationDb, {}, { commentNotificationId } ), 1 )
	
	commentNotification.read = false
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )
	
end

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

function WFCatNotificationTest.rxTestSetVisitedNotification( rxTest )

	local notificationDb = notificationDbSetUp( rxTest )

	local notificationObs = rxTest:observe( WFCatNotification.notificationList( notificationDb ) )
	rxTest:finally( function()
		notificationObs:dispose()
	end )

	notificationObs:expectData( {} )
	
	local commentNotification = WFCatNotification.DEBUG_synthesizeFieldsAndReverse( 
		addOneCommentNotification( rxTest, notificationDb ) )
	local commentNotificationId = commentNotification.notificationId
	
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )
		
	rxTest:expectSingleValue( WFCatNotification.setVisitedNotification( notificationDb, { commentNotificationId } ), 1 )
	
	commentNotification.visited = true
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )

	-- set to unvisited
	rxTest:expectSingleValue( WFCatNotification.setVisitedNotification( notificationDb, {}, { commentNotificationId } ), 1 )
	
	commentNotification.visited = false
	notificationObs:expectDataWithinTime( 2, {
		commentNotification
	} )
	
end

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

function WFCatNotificationTest.rxTestNotificationInfoTable( rxTest )

	rxTest:setTimeLimit(10)

	local notificationDb = notificationDbSetUp( rxTest )
	
	rxTest:waitFor( notificationDb:bulkInsertOrReplace( "notificationInfo", 
															{{ "previousLink", "http://previousLink" }} ) )
	
	local notificationUnreadCountObs = rxTest:observe( WFCatNotification.notificationUnreadCount( notificationDb ) )
	rxTest:finally( function()
		notificationUnreadCountObs:dispose()
	end )
	
	notificationUnreadCountObs:expectData( 0 )
	
	rxTest:observe( notificationDb:query({
			sql = "SELECT value FROM notificationInfo WHERE key = ?",
			"previousLink"
		}))
		:expectDataWithinTime( 2, {{ "http://previousLink" }} )
		:dispose()
	
end

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

function WFCatNotificationTest.rxTestDeleteNotificationsOlderThan( rxTest )
	
	rxTest:setTimeLimit( 10 )
	
	local notificationDb = notificationDbSetUp( rxTest )
	
	local sevenDaysAgo = KSDate.shiftIso8601DateTime( KSDate.timeInIso8601Format(), - ( 7 * 24 * 60 * 60 ) )
	local tenDaysAgo = KSDate.shiftIso8601DateTime( KSDate.timeInIso8601Format(), - ( 10 * 24 * 60 * 60 ) )
	
	local notificationObs = rxTest:observe( WFCatNotification.notificationList( notificationDb ) )
	rxTest:finally( function()
		notificationObs:dispose()
	end )
	
	local favorite = WFCatNotification.DEBUG_synthesizeFieldsAndReverse(
		addOneFavoriteNotification( rxTest, notificationDb, sevenDaysAgo ) )
	local comment = WFCatNotification.DEBUG_synthesizeFieldsAndReverse(
		addOneCommentNotification( rxTest, notificationDb, tenDaysAgo ) )
	
	notificationObs:expectDataWithinTime( 2, {
			favorite,
			comment
		} )
	
	rxTest:waitFor( WFCatNotification.deleteNotificationsOlderThan( notificationDb, 15 ) )
	
	notificationObs:expectDataWithinTime( 2, {
			favorite,
			comment
		} )
	
	rxTest:waitFor( WFCatNotification.deleteNotificationsOlderThan( notificationDb, 9 ) )
	
	notificationObs:expectDataWithinTime( 2, {
			favorite,
		} )
		
	rxTest:waitFor( WFCatNotification.deleteNotificationsOlderThan( notificationDb, 5 ) )
	
	notificationObs:expectDataWithinTime( 2, { } )
		
end

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

return WFRxTestCase.wrapSuite( 'WFCatNotificationTest', WFCatNotificationTest )