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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain 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 may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  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'

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

	-- WF.oz_client.managed_catalog
local WFOzSyncConstants = require "WFOzSyncConstants"

	-- WF.core.os
local WFPlatformInfo = require 'WFPlatformInfo'

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

local LrmSyncManagerTest = {}

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

local function checkSubscriptionOrTrialSync( rxTest, syncManager, 
											isWiFiOnlySyncB, reachabilityB, forceUpgradeB,
											isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
											
	isWiFiOnlySyncB:onNext( true )
	reachabilityB:onNext( 'wifi' )
	forceUpgradeB:onNext( true )
	isAuthenticatedUserB:onNext( true )
	syncEnabledB:onNext( true )
	isAppInBackgroundB:onNext( false )
	setIsUploadingB:onNext( true )
	
	local obs = rxTest:observe( syncManager._syncActivityControl )
	
	obs:expectData( false, true, false, false, false )	-- shouldSync, hasOzCatalog, isResidualMode, isBinaryUploading, isAppInBackground
	
	-- forceUpgraded
	forceUpgradeB:onNext( false )
	obs:expectData( true, true, false, true, false )
	
	-- reachable & isWifiOnly
	reachabilityB:onNext( 'wwan' )
	obs:expectData( false, true, false, false, false )
	
	isWiFiOnlySyncB:onNext( false )
	obs:expectData( true, true, false, true, false )
	
	reachabilityB:onNext( 'unreachable' )
	obs:expectData( false, true, false, false, false )
	
	reachabilityB:onNext( 'wifi' )
	obs:expectData( true, true, false, true, false )
	
	-- syncEnabled
	syncEnabledB:onNext( false )
	obs:expectData( false, true, false, false, false )
	
	syncEnabledB:onNext( true )
	obs:expectData( true, true, false, true, false )
	
	-- isAppInBackground
	isAppInBackgroundB:onNext( true )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( false, true, false, false, true )
	else
		obs:expectData( true, true, false, true, true )
	end
	
	isAppInBackgroundB:onNext( false )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( true, true, false, true, false )
	else
		obs:expectData( true, true, false, true, false )
	end

	if WFPlatformInfo.isAndroid then
		
		-- setIsUploading
		setIsUploadingB:onNext( false )
		obs:expectData( true, true, false, false, false )
		
		setIsUploadingB:onNext( true )
		obs:expectData( true, true, false, true, false )
		
	end

end

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

local function checkResidualModeSync( rxTest, syncManager, 
									isWiFiOnlySyncB, reachabilityB, forceUpgradeB,
									isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
											
	isWiFiOnlySyncB:onNext( true )
	reachabilityB:onNext( 'wifi' )
	forceUpgradeB:onNext( true )
	isAuthenticatedUserB:onNext( true )
	syncEnabledB:onNext( true )
	isAppInBackgroundB:onNext( false )
	setIsUploadingB:onNext( true )
	
	local obs = rxTest:observe( syncManager._syncActivityControl )
	
	obs:expectData( false, true, true, false, false )	-- shouldSync, hasOzCatalog, isResidualMode, isBinaryUploading, isAppInBackground
	
	-- forceUpgraded
	forceUpgradeB:onNext( false )
	obs:expectData( true, true, true, false, false )
	
	-- reachable & isWifiOnly
	reachabilityB:onNext( 'wwan' )
	obs:expectData( false, true, true, false, false )
	
	isWiFiOnlySyncB:onNext( false )
	obs:expectData( true, true, true, false, false )
	
	reachabilityB:onNext( 'unreachable' )
	obs:expectData( false, true, true, false, false )
	
	reachabilityB:onNext( 'wifi' )
	obs:expectData( true, true, true, false, false )
	
	-- syncEnabled
	syncEnabledB:onNext( false )
	obs:expectData( false, true, true, false, false )
	
	syncEnabledB:onNext( true )
	obs:expectData( true, true, true, false, false )

	-- isAppInBackground
	isAppInBackgroundB:onNext( true )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( false, true, true, false, true )
	else
		obs:expectData( true, true, true, false, true )
	end
	
	isAppInBackgroundB:onNext( false )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( true, true, true, false, false )
	else
		obs:expectData( true, true, true, false, false )
	end
	

	if WFPlatformInfo.isAndroid then
	
		-- setIsUploading
		setIsUploadingB:onNext( false )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( true, true, true, false, false )
		
		setIsUploadingB:onNext( true )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( true, true, true, false, false )
		
	end

end

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

local function checkEntitlementCreatedSync( rxTest, syncManager, 
									isWiFiOnlySyncB, reachabilityB, forceUpgradeB,
									isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
											
	isWiFiOnlySyncB:onNext( true )
	reachabilityB:onNext( 'wifi' )
	forceUpgradeB:onNext( true )
	isAuthenticatedUserB:onNext( true )
	syncEnabledB:onNext( true )
	isAppInBackgroundB:onNext( false )
	setIsUploadingB:onNext( true )
	
	local obs = rxTest:observe( syncManager._syncActivityControl )
	
	obs:expectData( false, false, false, false, false )	-- shouldSync, hasOzCatalog, isResidualMode, isBinaryUploading, isAppInBackground
	
	-- forceUpgraded
	forceUpgradeB:onNext( false )
	obs:expectData( true, false, false, false, false )
	
	-- reachable & isWifiOnly
	reachabilityB:onNext( 'wwan' )
	obs:expectData( false, false, false, false, false )
	
	isWiFiOnlySyncB:onNext( false )
	obs:expectData( true, false, false, false, false )
	
	reachabilityB:onNext( 'unreachable' )
	obs:expectData( false, false, false, false, false )
	
	reachabilityB:onNext( 'wifi' )
	obs:expectData( true, false, false, false, false )
	
	-- syncEnabled
	syncEnabledB:onNext( false )
	obs:expectData( false, false, false, false, false )
	
	syncEnabledB:onNext( true )
	obs:expectData( true, false, false, false, false )

	-- isAppInBackground
	isAppInBackgroundB:onNext( true )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( false, false, false, false, true )
	else
		obs:expectData( true, false, false, false, true )
	end
	
	isAppInBackgroundB:onNext( false )
	
	if WFPlatformInfo.isAndroid then
		obs:expectData( true, false, false, false, false )
	else
		obs:expectData( true, false, false, false, false )
	end

	if WFPlatformInfo.isAndroid then
		
		-- setIsUploading
		setIsUploadingB:onNext( false )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( true, false, false, false, false )
		
		setIsUploadingB:onNext( true )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( true, false, false, false, false )
		
	end

end

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

local function checkEntitlementNilSync( rxTest, syncManager, 
									isWiFiOnlySyncB, reachabilityB, forceUpgradeB,
									isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
											
	isWiFiOnlySyncB:onNext( true )
	reachabilityB:onNext( 'wifi' )
	forceUpgradeB:onNext( true )
	isAuthenticatedUserB:onNext( false )
	syncEnabledB:onNext( true )
	isAppInBackgroundB:onNext( false )
	setIsUploadingB:onNext( true )
	
	local obs = rxTest:observe( syncManager._syncActivityControl )
	
	obs:expectData( false, false, false, false, false )	-- shouldSync, hasOzCatalog, isResidualMode, isBinaryUploading, isAppInBackground
	
	-- forceUpgraded
	forceUpgradeB:onNext( false )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	-- reachable & isWifiOnly
	reachabilityB:onNext( 'wwan' )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	isWiFiOnlySyncB:onNext( false )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	reachabilityB:onNext( 'unreachable' )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	reachabilityB:onNext( 'wifi' )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	-- syncEnabled
	syncEnabledB:onNext( false )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )
	
	syncEnabledB:onNext( true )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( false, false, false, false, false )

	-- isAppInBackground
	isAppInBackgroundB:onNext( true )
	
	if WFPlatformInfo.isAndroid then
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, true )
	else
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, true )
	end
	
	isAppInBackgroundB:onNext( false )
	
	if WFPlatformInfo.isAndroid then
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, false )
	else
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, false )
	end

	if WFPlatformInfo.isAndroid then
	
		-- isAppInBackground
		isAppInBackgroundB:onNext( true )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, true )
		
		isAppInBackgroundB:onNext( false )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, false )
		
		-- setIsUploading
		setIsUploadingB:onNext( false )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, false )
		
		setIsUploadingB:onNext( true )
		
		obs = rxTest:observe( syncManager._syncActivityControl )
		obs:expectData( false, false, false, false, false )
		
	end

end

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

local function checkEntitlementCreatedToTrialSync( rxTest, syncManager, 
												entitlementB, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, 
												isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	entitlementB:onNext( { status = 'created' } )
	isWiFiOnlySyncB:onNext( false )
	reachabilityB:onNext( 'wifi' )
	forceUpgradeB:onNext( false )
	isAuthenticatedUserB:onNext( true )
	syncEnabledB:onNext( true )
	isAppInBackgroundB:onNext( false )
	setIsUploadingB:onNext( true )
	
	local obs = rxTest:observe( syncManager._syncActivityControl )
	
	obs:expectData( true, false, false, false, false )	-- shouldSync, hasOzCatalog, isResidualMode, isBinaryUploading, isAppInBackground

	-- syncActivityControl remain the same. New library with new catalogId will be created.
	-- This syncManager from created catalogId should not start any oz catalog sync
	
	entitlementB:onNext( { status = 'trial' } )
	
	obs = rxTest:observe( syncManager._syncActivityControl )
	obs:expectData( true, false, false, false, false )

end

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

function LrmSyncManagerTest.rxTestSyncEnablementWithOzCatalog( rxTest )

	local LrmSyncManager = require 'LrmSyncManager'
	
	local catalog = require 'LrmCatalogTestHelper'.makeCatalogService()
	
	local catalogId = '12345678901234567890123456789012'
	local entitlementB = Rx.ReplaySubject( 1 )
	local isWiFiOnlySyncB = Rx.ReplaySubject( 1 )
	local reachabilityB = Rx.ReplaySubject( 1 )
	local forceUpgradeB = Rx.ReplaySubject( 1 )
	local isAuthenticatedUserB = Rx.ReplaySubject( 1 )
	local syncEnabledB =  Rx.ReplaySubject( 1 )
	local isAppInBackgroundB = Rx.ReplaySubject( 1 )
	local setIsUploadingB = Rx.ReplaySubject( 1 )
	local isGeoRestrictedAccountStream = Rx.BehaviorSubject( false )
	
	local syncManager = LrmSyncManager {
		catalog = catalog,
		catalogId = catalogId,
		isWiFiOnlySync = isWiFiOnlySyncB,
		isReachable = reachabilityB,
		forceUpgrade = forceUpgradeB,
		isAuthenticatedUser = isAuthenticatedUserB,
		entitlement = entitlementB,
		syncEnabled = syncEnabledB,
		isAppInBackground = isAppInBackgroundB,
		setIsUploading = setIsUploadingB,
		isGeoRestrictedAccountStream = isGeoRestrictedAccountStream
	}
	
	-- this test is a bit subtle - the syncManager uses distinctUntilChanged, so we must see to it that values are
	-- always alternating
	
	
	-- subscription & trial ----------------------------------------------------
	
	entitlementB:onNext( { status = 'subscription' } )
	checkSubscriptionOrTrialSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	entitlementB:onNext( { status = 'trial' } )
	checkSubscriptionOrTrialSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )

	-- residual mode: subscription expired & trial expired ---------------------

	entitlementB:onNext( { status = 'subscription_expired' } )
	checkResidualModeSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	entitlementB:onNext( { status = 'trial_expired' } )
	checkResidualModeSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	syncManager:close()
	
end

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

function LrmSyncManagerTest.rxTestSyncEnablementWithoutOzCatalog( rxTest )

	local LrmSyncManager = require 'LrmSyncManager'
	
	local catalog = require 'LrmCatalogTestHelper'.makeCatalogService()
	
	local catalogId = WFOzSyncConstants.kGlobalDocumentId -- 00000000000000000000000000000000
	local entitlementB = Rx.ReplaySubject( 1 )
	local isWiFiOnlySyncB = Rx.ReplaySubject( 1 )
	local reachabilityB = Rx.ReplaySubject( 1 )
	local forceUpgradeB = Rx.ReplaySubject( 1 )
	local isAuthenticatedUserB = Rx.ReplaySubject( 1 )
	local syncEnabledB =  Rx.ReplaySubject( 1 )
	local isAppInBackgroundB = Rx.ReplaySubject( 1 )
	local setIsUploadingB = Rx.ReplaySubject( 1 )
	local isGeoRestrictedAccountStream = Rx.BehaviorSubject( false )
	
	local syncManager = LrmSyncManager {
		catalog = catalog,
		catalogId = catalogId,
		isWiFiOnlySync = isWiFiOnlySyncB,
		isReachable = reachabilityB,
		forceUpgrade = forceUpgradeB,
		isAuthenticatedUser = isAuthenticatedUserB,
		entitlement = entitlementB,
		syncEnabled = syncEnabledB,
		isAppInBackground = isAppInBackgroundB,
		setIsUploading = setIsUploadingB,
		isGeoRestrictedAccountStream = isGeoRestrictedAccountStream
	}
	
	-- this test is a bit subtle - the syncManager uses distinctUntilChanged, so we must see to it that values are
	-- always alternating
	

	-- entitlement created -----------------------------------------------------
	-- Freemium with login (isAuthenticatedUser == true), but no Oz catalog
	
	entitlementB:onNext( { status = 'created' } )
	checkEntitlementCreatedSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	-- entitlement nil ---------------------------------------------------------
	-- Freemium without login, no sync should be allowed

	entitlementB:onNext( nil )
	checkEntitlementNilSync( rxTest, syncManager, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )

	syncManager:close()
	
end

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

function LrmSyncManagerTest.rxTestSyncWithEntitlementTransit( rxTest )

	local LrmSyncManager = require 'LrmSyncManager'
	
	local catalog = require 'LrmCatalogTestHelper'.makeCatalogService()
	
	local catalogId = WFOzSyncConstants.kGlobalDocumentId -- 00000000000000000000000000000000
	local entitlementB = Rx.ReplaySubject( 1 )
	local isWiFiOnlySyncB = Rx.ReplaySubject( 1 )
	local reachabilityB = Rx.ReplaySubject( 1 )
	local forceUpgradeB = Rx.ReplaySubject( 1 )
	local isAuthenticatedUserB = Rx.ReplaySubject( 1 )
	local syncEnabledB =  Rx.ReplaySubject( 1 )
	local isAppInBackgroundB = Rx.ReplaySubject( 1 )
	local setIsUploadingB = Rx.ReplaySubject( 1 )
	local isGeoRestrictedAccountStream = Rx.BehaviorSubject( false )
	
	local syncManager = LrmSyncManager {
		catalog = catalog,
		catalogId = catalogId,
		isWiFiOnlySync = isWiFiOnlySyncB,
		isReachable = reachabilityB,
		forceUpgrade = forceUpgradeB,
		isAuthenticatedUser = isAuthenticatedUserB,
		entitlement = entitlementB,
		syncEnabled = syncEnabledB,
		isAppInBackground = isAppInBackgroundB,
		setIsUploading = setIsUploadingB,
		isGeoRestrictedAccountStream = isGeoRestrictedAccountStream
	}
	
	-- this test is a bit subtle - the syncManager uses distinctUntilChanged, so we must see to it that values are
	-- always alternating
	

	-- entitlement created -> trial --------------------------------------------

	checkEntitlementCreatedToTrialSync( rxTest, syncManager, entitlementB, isWiFiOnlySyncB, reachabilityB, forceUpgradeB, isAuthenticatedUserB, syncEnabledB, isAppInBackgroundB, setIsUploadingB )
	
	-- no need to test nil entitlement to created or trial
	-- whenever nil entitlement transit to authenticated user, the old catalog will always been deleted correctly
	
	syncManager:close()
	
end

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

return WFRxTestCase.wrapSuite( 'LrmSyncManagerTest', LrmSyncManagerTest )
