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

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

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

local Rx = require "Rx"

local OzFilePaths = require "OzFilePaths"
local KSData = require "KSData"
local KSTableUtils = require "KSTableUtils"
local KSPathUtils = require "KSPathUtils"

local WFCrypto = require "WFCrypto"

local WFRxHttpServerUtils = require "WFRxHttpServerUtils"

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

local derefOpt = assert( KSTableUtils.derefOpt )


local typeToPrefix = {
	preview = 'pv_',
	thumbnail2x= 'th_',
}

local contentTypeMap = {
	jpg = 'image/jpeg',
	jpeg = 'image/jpeg',
	png = 'image/png',
	tiff = 'image/tiff',
	gif = 'image/gif',
	mpeg = 'video/mpeg',
	mpg = 'video/mpeg',
	mp4 = 'video/mp4',
	qt = 'video/quicktime',
	mov = 'video/quicktime',
	avi = 'video/x-msvideo',
	ogg = 'video/ogg',
	ogv = 'video/ogg'
}

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

local function verifyPeer( info, catalog )

	if not info.clientCert then
		return false, { statusCode = 401, data = 'no client cert' }
	end

	local catalogHash = KSData.make( catalog:ozCatalogSpec():catalogId() ):digest( 'SHA224' )

	local splitSubject = WFCrypto.splitSubject( info.clientCert.subject )

	local requiredSubject = {
		C = 'US',
		ST = 'California',
		L = 'San Jose',
		O = 'Adobe Inc.',
		OU = 'Digital Imaging',
		CN = catalogHash
	}

	if not KSTableUtils.deepEquals( splitSubject, requiredSubject ) then
		return false, { statusCode = 401, data = 'go away' }
	end

	return true
end

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

local handlers = {
	{ '^/hello$', { 'GET' }, function( path, info, catalog )

		local verified, response = verifyPeer( info, catalog )

		if not verified then
			return Rx.Observable.just( response )
		end

		return Rx.Observable.just { contentType = 'text/plain', data = 'moin' }
	end },
	{ '^/assets/(%x+)/(%x+)/(%x+)/(%w+)\.(%w+)$', { 'GET' }, function( path, info, catalog )

		local verified, response = verifyPeer( info, catalog )

		if not verified then
			return Rx.Observable.just( response )
		end

		if #info.matches ~= 5 then
			return Rx.Observable.just{ statusCode = 400, data = 'Bad Request' }
		end

		for i = 1, 2 do
			if #info.matches[ i ] ~= 32 then
				return Rx.Observable.just{ statusCode = 400, data = 'Bad Request' }
			end
		end

		if #info.matches[ 3 ] ~= 32 and #info.matches[ 3 ] ~= 64 then
			return Rx.Observable.just{ statusCode = 400, data = 'Bad Request' }
		end

		local catalogId, assetId, contentId, renditionName, ext = unpack( info.matches )

		if catalogId ~= catalog:ozCatalogSpec():catalogId() then
			return Rx.Observable.just{ statusCode = 400, data = 'Bad Request' }
		end
		
		local contentType = 'application/octet-stream'

		if ext then

			contentType = contentTypeMap[ ext:lower() ]
			if not contentType then
				contentType = 'application/octet-stream'
			end

		end

		local basePath = OzFilePaths.getCatalogBasePath( catalogId )
		local filePath

		filePath = OzFilePaths.getRelativeBlobPath( assetId, catalogId )
		filePath = KSPathUtils.child( basePath, filePath )

		local prefix = typeToPrefix[ renditionName ]

		if prefix then

			filePath = KSPathUtils.child( filePath, prefix .. contentId .. '.' .. ext )

			return Rx.Observable.just { contentType = contentType, filePath = filePath }
		end

		if renditionName ~= 'master' and renditionName ~= 'proxy' then
			return Rx.Observable.just{ statusCode = 400, data = 'Bad Request' }
		end

		-- the 'master' is stored as 'original' in cacheReferences
		if renditionName == 'master' then
			renditionName = 'original'
		end

		-- for proxy and master, we need to query the indexStore

		return catalog:indexStore():queryOnce{
				sql = 'SELECT path from cacheReferences WHERE assetId = ? AND renditionName = ?',
				singleColumnQuery = true,
				assetId,
				renditionName
			}
			:map( function( paths )

				local path = derefOpt( paths, 1 )
				if not path then
					return { statusCode = 404, data = string.format('%s %s not found', renditionName, assetId ) }
				end

				filePath = KSPathUtils.child( basePath, path )

				return { contentType = contentType, filePath = filePath }

			end )

	end },
}

local LriP2PHttpServerHandlers = {}

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

function LriP2PHttpServerHandlers.startRequest( uri, requestParams, ... )

	return { 
		value = WFRxHttpServerUtils.startRequest( handlers, uri, requestParams, ... )
	}

end

return LriP2PHttpServerHandlers
