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

WFCatTestSession.lua

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

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'
local Observable = Rx.Observable


	-- WF.core.logging
local WFLogger = require 'WFLogger'

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

	-- WF.core.utils
local WFArguments = require 'WFArguments'
local WFCloseSupport = require 'WFCloseSupport'
local WFDebugTraceback = require 'WFDebugTraceback'

	-- WF.oz.client.account
local WFOzUserTestSession = require 'WFOzUserTestSession'

   -- WF.oz_client.managed_catalog
local WFCatUser = require 'WFCatUser'
local WFCatMockCatalog = require 'WFCatMockCatalog'

	-- WF.sqlite.doc_store
local WFRxDocStore = require 'WFRxDocStore'


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

local logger = WFLogger 'WFCatTestSession'
--	:setLevel 'debug'

local check = assert( WFArguments.check )


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

-- @mark WFCatTestSession class

--------------------------------------------------------------------------------
--[[
	\class WFCatTestSession

	A \c WFCatTestSession is testing infrastructure code that sets up
	and destroys (when done) a temporary catalog on the debug server ("ozstage").
]]--

local WFCatTestSession = {

	_traceback = false,
		-- (WFDebugTraceback) who created this object?

	_rxTest = false,
		-- (WFRxTestCaseRunner) test that we're running with

	_catalogClassType = false,
		-- (string) WFCatalog subclass to use when creating the catalog

	_indexSpecScript = false,
		-- (string) name of script to use for index store
	
	_userTestSession = false,
		-- (WFOzUserTestSession)

	_docStore = false,
		-- (WFRxDocStore)

	_ozUserId = false,
		-- (ReplayObservable< Oz user UUID >)

	_wfCatUser = false,
		-- (ReplayObservable< WFCatUser >) will resolve to a WFCatUser object when ready

	_wfCatSpec = false,
		-- (ReplayObservable< WFCatSpec >) will resolve to a WFCatSpec object when ready

	_wfCatalog = false,
		-- (ReplayObservable< WFCatalog >) will resolve to a WFCatalog object when ready

	WFCloseSupport.addCloseSupportMethods,

}

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

function WFCatTestSession:__init( rxTest, optCatalogClassType, optIndexSpecScript, optArgs )

	check( 'WFCatTestSession', 'WFRxTestCaseRunner', '?string', '?string', '?table' )

	optArgs = optArgs or {}

	self._traceback = WFDebugTraceback.traceback
						{ 'WFCatTestSession.lua', 'Class.lua' }

	self._rxTest = rxTest
	
	self._catalogClassType = optCatalogClassType or 'WFCatalog'

	self._indexSpecScript = optIndexSpecScript

	self:setOwned { _docStore = WFRxDocStore( ':memory:' ) }

	self._userTestSession = WFOzUserTestSession( rxTest, { 
			v2 = true,
			testName = optArgs.testName
		} )

	rxTest:addCloseTarget( self )

	WFCloseSupport.mustClose( self )

end

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

function WFCatTestSession:close()

	if WFPlatformInfo.isWindows then
		local KSPrefsImpLua = require 'KSPrefsImpLua'
		KSPrefsImpLua.deletePrefsFile()
	end

end

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

function WFCatTestSession:docStore()

	check( 'WFCatTestSession' )

	return self._docStore

end

--------------------------------------------------------------------------------
--[[!
	\brief Acquire a temporary clean user account for use with this test catalog.

	\return <code>ReplayObservable< Oz user UUID ></code> ID of an Oz user account
		that has been logged in and that has no catalogs or other data
]]--

function WFCatTestSession:ozUserId()

	check( 'WFCatTestSession' )

	logger:info( "WFCatTestSession:ozUserId()" )

	if self._ozUserId then
		return self._ozUserId
	end

	self._ozUserId = self._userTestSession:getCleanOzAccount()
		:publishLast()

	self._ozUserId:connect()

	return self._ozUserId

end

--------------------------------------------------------------------------------
--[[!
	\brief Acquire a temporary clean user for use with this test catalog
		and return a corresponding WFCatUser object.

	\return <code>ReplayObservable< WFCatUser ></code>
]]--

function WFCatTestSession:wfCatUser()

	-- TODO [scouten 2015-07-20]: Consider whether this belongs in
	-- WFOzUserTestSession.

	check( 'WFCatTestSession' )

	if self._wfCatUser then
		return self._wfCatUser
	end

	logger:info( "WFCatTestSession:wfCatUser()" )

	self._wfCatUser = self:ozUserId()

		:flatMapLatest( function( ozUserId )

			logger:infof( "WFCatTestSession:wfCatUser() - got user ID %s", ozUserId )

			local wfCatUser = WFCatUser( self._userTestSession:ozServerBaseUrl(), ozUserId, ':memory:' )

			-- TODO [scouten 2015-07-20]: Spin up user info sync agent.
			-- (Ignore for now.)

			self:addCloseTarget( wfCatUser )

			return wfCatUser:storeTokens( self._userTestSession:accessAndRefreshTokens() )
				:concat( Observable.just( wfCatUser ) )

		end )
		:publishLast()

	self._wfCatUser:connect()

	return self._wfCatUser

end

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

function WFCatTestSession:catalogSpec()

	check( 'WFCatTestSession' )

	if self._wfCatSpec then
		return self._wfCatSpec
	end

	logger:info( "WFCatTestSession:catalogSpec()" )

	self._wfCatSpec = self:wfCatUser()

		-- Now create a new test catalog for this user.

		:flatMapLatest( function( user )

			logger:infof( "WFCatTestSession:catalogSpec() - got user %s", user:userId() )

			return user:createCatalog( "WFCatTestSession" )

		end )

		:publishLast()

	self._wfCatSpec:connect()

	return self._wfCatSpec

end

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

function WFCatTestSession:catalog()

	check( 'WFCatTestSession' )

	if self._wfCatalog then
		return self._wfCatalog
	end

	logger:info( "WFCatTestSession:catalog()" )

	self._wfCatalog = self:catalogSpec()

		-- Now create a new test catalog for this user.

		:take( 1 )

		:map( function( catalogSpec )

			logger:info( "WFCatTestSession:catalog() - got catalogSpec" )

			local result = WFCatMockCatalog.createWFCatalogForTestWithSpec( self._rxTest, catalogSpec, self._catalogClassType, self._indexSpecScript )

			return result

		end )

		:publishLast()

	self._wfCatalog:connect()

	return self._wfCatalog

end

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

function WFCatTestSession:reloadAccessAndRefreshTokens()

	check( 'WFCatTestSession' )

	return self._userTestSession:reloadAccessAndRefreshTokens()

end

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

return Rx.Class 'WFCatTestSession'( WFCatTestSession )
