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

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

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

local WFArguments = require 'WFArguments'
local WFLogger = require 'WFLogger'
local WFPlatformInfo = require 'WFPlatformInfo'
local WFCapabilities = require 'WFCapabilities'


local mustLoadWFAnalyticsImp = not  WFCapabilities.getCapability( 'WFAnalytics.optOut' )

local WFAnalyticsImp 
if mustLoadWFAnalyticsImp then
	-- require WFAnalyticsImp which *must* be provided by the client
	-- there is no default analytics implementation provided by WF
	WFAnalyticsImp = require 'WFAnalyticsImp'
else
	-- default no-op impl for unit tests/clients who don't want analytics
	WFAnalyticsImp = {} 

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

local logger = WFLogger( 'WFAnalytics' )

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

-- @mark WFAnalytics namespace

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

local WFAnalytics = {}

--------------------------------------------------------------------------------
-- DEPRECATED: Please use trackEvent instead
function WFAnalytics.trackAction( action, ... )
	
	logger:warnf( "WFAnalytics.trackAction is deprecated, please use WFAnalytics.trackEvent" )
	if WFAnalyticsImp and WFAnalyticsImp.trackAction then
		WFAnalyticsImp.trackAction( action, ... )
	end

end

--[[
	\brief Sends an analytics event described by the table. Each event table should have
	the following standard fields in it
	
		category: The broad category of event
		action: The specific event that is being tracked
		detail: (Optional) Additional details about the event being tracked
		
	Other fields are allowed in the table, but may not end in the underlying Imp's analytics
	tracking
	
]]--
--------------------------------------------------------------------------------

function WFAnalytics.trackEvent( detailTable )
	
	WFArguments.check( 'table' )
	
	if WFAnalyticsImp and WFAnalyticsImp.trackEvent then
	
		local frameworkVersion = WFPlatformInfo.getFrameworkVersion()
	
		if detailTable[ 'event.workflow' ] then
			logger:warnf( "event.workflow is a protected field, and will be overwritten with 'Debug'" )
		end
	
		detailTable[ 'event.workflow' ] = 'Debug' -- WF-1906
		
		detailTable[ 'env.fw.name' ] = 'WF' -- WF-1906
		detailTable[ 'env.fw.version' ] = frameworkVersion -- WF-1906
		detailTable[ 'lr.wf.version' ] = frameworkVersion
		
		-- WF-2093
		if WFPlatformInfo.isAndroid then
			detailTable[ 'lr.wf.commit' ] = WFPlatformInfo.getBuild()
		else
			detailTable[ 'lr.wf.commit' ] = WFPlatformInfo.getFrameworkBuildNumber()
		end
		
		detailTable[ 'event.subcategory' ] = detailTable[ 'event.subcategory' ] or "Unknown"
		detailTable[ 'event.subtype' ] = detailTable[ 'event.subtype' ] or "unknown"
		
		--WF-2425
		local error_code = detailTable[ 'event.error_code' ]
		local error_desc = detailTable[ 'event.error_desc' ]

		detailTable[ 'event.error_code' ] = error_code and WFAnalytics.sanitizeForAnalytics( tostring(error_code) )
		detailTable[ 'event.error_desc' ] = error_desc and WFAnalytics.sanitizeForAnalytics( error_desc )

		WFAnalyticsImp.trackEvent( detailTable )
		
	end
	
end

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

--[[

	\brief Extract secrets from a URL/error_code/error_desc making it safe for logging

	\param str (string) - The destination string

	\return string

	Note: This is tested via WFCatBinaryUploaderTest.rxTestSanitizeDirectUploadUrlForAnalytics.

]]

function WFAnalytics.sanitizeForAnalytics( str )

	str = str and str:gsub( "&X%-Amz%-Security%-Token=.*&", "&X-Amz-Security-Token=***&" )
	str = str and str:gsub( "&content_type={content_type}", "" )

	return str

end

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

--[[

	\brief Sends a binary download failure analytics event.

	\param failureInfo (table) - A table of request and failure info:

		{
			docId = <docId>,
			url = <url>,
			responseData = <request response>,
			headers = <request headers>,
			isDirectDownload = <boolean>,
		}

	\return void

]]

function WFAnalytics.trackEventDownloadFailure( failureInfo )

	local errorEvent = {}

	errorEvent[ 'event.downloadMethod' ] = failureInfo.isDirectDownload and 'oz_redirected_download' or 'oz_download'
	errorEvent[ 'event.type' ] = 'error'
	errorEvent[ 'event.appWorkflow' ] = 'SYNC'
	errorEvent[ 'event.subcategory' ] = 'Binary_download'
	errorEvent[ 'event.url' ] = WFAnalytics.sanitizeForAnalytics( failureInfo.url )
	errorEvent[ 'event.error_type' ] = 'BinaryDownload.Error'
	errorEvent[ 'content.id' ] = failureInfo.docId

	local errorCode = failureInfo.headers and failureInfo.headers.status_code or 'nil'

	local responseDataString = tostring( failureInfo.responseData )

	if not failureInfo.headers then

		-- Modern native HTTP implementations put "wf_err_timeout" in the error JSON on timeout

		if ( string.match( responseDataString, "wf_err_timeout" )
				or string.match( responseDataString, "timed out" ) ) then

			errorCode = "timeout"

		end

		errorEvent[ 'event.subtype' ] = 'os'
		errorEvent[ 'event.error_code' ] = errorCode
		errorEvent[ 'event.error_desc' ] = responseDataString -- error message

	else

		local ozRequestId = failureInfo.headers[ 'X-Request-Id' ]

		errorEvent[ 'event.subtype' ] = 'api'
		errorEvent[ 'event.error_code' ] = errorCode
		errorEvent[ 'event.error_desc' ] = responseDataString -- oz error response
		errorEvent[ 'event.context_guid' ] = ozRequestId

	end

	WFAnalytics.trackEvent( errorEvent )

end

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

return WFAnalytics
