return Rodux.createReducer({},{[SetOwnedAssets.name]=function(J,k)local d={}local n=J[k.assetTypeId]and J[k.assetTypeId]or{}for J,k in pairs(n)do d[k]=k end for J,k in pairs(k.assets)do if not d[k]then n[#n+1]=k end end return Cryo.Dictionary.join(J,{[k.assetTypeId]=n})end,[GrantAsset.name]=function(J,k)if GetAENewNavigationEnabled()then local d={}local n=tostring(k.assetTypeId)local A=tostring(k.assetId)local Q=AssetTypeToSearchUuids[n]if not Q then return J end for k,n in ipairs(Q)do local Q=J[n]and J[n]or{}local u={A}local C=false for J,k in ipairs(Q)do if k==A then C=true break else u[J+1]=k end end if not C then d[n]=u end end if next(d)then return Cryo.Dictionary.join(J,d)end return J else local d=tostring(k.assetTypeId)local n=tostring(k.assetId)local A=J[d]and J[d]or{}local Q={n}for k,d in ipairs(A)do if d==n then return J else Q[k+1]=d end end return Cryo.Dictionary.join(J,{[d]=Q})end end;[RevokeAsset.name]=function(J,k)if GetAENewNavigationEnabled()then local d={}local n=tostring(k.assetTypeId)local A=tostring(k.assetId)local Q=AssetTypeToSearchUuids[n]if not Q then return J end for k,n in ipairs(Q)do local Q=J[n]and J[n]or{}local u=Cryo.List.removeValue(Q,A)if#Q~=#u then d[n]=u end end if next(d)then return Cryo.Dictionary.join(J,d)end return J else local d=tostring(k.assetTypeId)local n=tostring(k.assetId)local A=J[d]and J[d]or{}local Q=Cryo.List.removeValue(A,n)return Cryo.Dictionary.join(J,{[d]=Q})end end,[GrantOutfit.name]=function(J,k)local d=tostring(k.outfitId)local n=J[AvatarEditorConstants.CharacterKey]or{}local A={d}for k,n in ipairs(n)do if n==d then return J else A[k+1]=n end end return Cryo.Dictionary.join(J,{[AvatarEditorConstants.CharacterKey]=A})end;[RevokeOutfit.name]=function(J,k)local d=tostring(k.outfitId)local n=J[AvatarEditorConstants.CharacterKey]or{}local A=Cryo.List.removeValue(n,d)return Cryo.Dictionary.join(J,{[AvatarEditorConstants.CharacterKey]=A})end})


return Rodux.createReducer({}, {
	[SetOwnedAssets.name] = function(state, action)
		local checkForDups = {}
		local currentAssets = state[action.assetTypeId] and state[action.assetTypeId] or {}

		for _, assetId in pairs(currentAssets) do
			checkForDups[assetId] = assetId
		end

		for _, assetId in pairs(action.assets) do
			if not checkForDups[assetId] then
				currentAssets[#currentAssets + 1] = assetId
			end
		end

		return Cryo.Dictionary.join(state, {[action.assetTypeId] = currentAssets})
	end,

	[GrantAsset.name] = function(state, action)
		if GetAENewNavigationEnabled() then
			local updatedCategories = {}

			local assetTypeId = tostring(action.assetTypeId)
			local newAssetId = tostring(action.assetId)

			local searchUuids = AssetTypeToSearchUuids[assetTypeId]
			if not searchUuids then
				return state
			end

			for _, searchUuid in ipairs(searchUuids) do
				local currentAssets = state[searchUuid] and state[searchUuid] or {}

				local updatedAssets = { newAssetId }
				local owned = false

				for i, assetId in ipairs(currentAssets) do
					if assetId == newAssetId then
						owned = true
						break
					else
						updatedAssets[i + 1] = assetId
					end
				end

				-- Do nothing if this asset is already owned.
				if not owned then
					updatedCategories[searchUuid] = updatedAssets
				end
			end

			if next(updatedCategories) then
				return Cryo.Dictionary.join(state, updatedCategories)
			end

			return state
		else
			local assetTypeId = tostring(action.assetTypeId)
			local newAssetId = tostring(action.assetId)
			local currentAssets = state[assetTypeId] and state[assetTypeId] or {}

			local updatedAssets = { newAssetId }

			for i, assetId in ipairs(currentAssets) do
				-- Do nothing if this asset is already owned.
				if assetId == newAssetId then
					return state
				else
					updatedAssets[i + 1] = assetId
				end
			end

			return Cryo.Dictionary.join(state, {[assetTypeId] = updatedAssets})
		end
	end,

	[RevokeAsset.name] = function(state, action)
		if GetAENewNavigationEnabled() then
			local updatedCategories = {}

			local assetTypeId = tostring(action.assetTypeId)
			local assetToRevokeId = tostring(action.assetId)

			local searchUuids = AssetTypeToSearchUuids[assetTypeId]
			if not searchUuids then
				return state
			end

			for _, searchUuid in ipairs(searchUuids) do
				local currentAssets = state[searchUuid] and state[searchUuid] or {}
				local updatedAssets = Cryo.List.removeValue(currentAssets, assetToRevokeId)

				-- Do nothing if this asset is not owned.
				if #currentAssets ~= #updatedAssets then
					updatedCategories[searchUuid] = updatedAssets
				end
			end

			if next(updatedCategories) then
				return Cryo.Dictionary.join(state, updatedCategories)
			end

			return state
		else
			local assetTypeId = tostring(action.assetTypeId)
			local assetToRevokeId = tostring(action.assetId)
			local currentAssets = state[assetTypeId] and state[assetTypeId] or {}

			local updatedAssets = Cryo.List.removeValue(currentAssets, assetToRevokeId)

			return Cryo.Dictionary.join(state, {[assetTypeId] = updatedAssets})
		end
	end,

	[GrantOutfit.name] = function(state, action)
		local actionOutfitId = tostring(action.outfitId)
		local currentOutfits = state[AvatarEditorConstants.CharacterKey] or {}

		local updatedOutfits = { actionOutfitId }

		for i, outfitId in ipairs(currentOutfits) do
			-- Do nothing if this costume is already owned.
			if outfitId == actionOutfitId then
				return state
			else
				updatedOutfits[i + 1] = outfitId
			end
		end

		return Cryo.Dictionary.join(state, {[AvatarEditorConstants.CharacterKey] = updatedOutfits})
	end,

	[RevokeOutfit.name] = function(state, action)
		local outfitId = tostring(action.outfitId)
		local currentOutfits = state[AvatarEditorConstants.CharacterKey] or {}
		local costumeList = Cryo.List.removeValue(currentOutfits, outfitId)

		return Cryo.Dictionary.join(state, {[AvatarEditorConstants.CharacterKey] = costumeList})
	end
})
