 		return .copy
 	}
 
+	func validateSingleLocalFeedDrop(_ outlineView: NSOutlineView, _ draggedFeed: PasteboardFeed, _ parentNode: Node, _ index: Int) -> NSDragOperation {
+		// A local feed should always drag on to an Account or Folder node, and we can provide an index.
+		guard let dropTargetNode = ancestorThatCanAcceptLocalFeed(parentNode) else {
+			return SidebarOutlineDataSource.dragOperationNone
+		}
+		if nodeHasChildRepresentingDraggedFeed(dropTargetNode, draggedFeed) {
+			return SidebarOutlineDataSource.dragOperationNone
+		}
+		let updatedIndex = indexWhereDraggedFeedWouldAppear(dropTargetNode, draggedFeed)
+		if parentNode !== dropTargetNode || index != updatedIndex {
+			outlineView.setDropItem(dropTargetNode, dropChildIndex: updatedIndex)
+		}
+		return .move
+	}
+
+	func validateLocalFeedsDrop(_ outlineView: NSOutlineView, _ draggedFeeds: Set<PasteboardFeed>, _ parentNode: Node, _ index: Int) -> NSDragOperation {
+		// Local feeds should always drag on to an Account or Folder node, and index should be NSOutlineViewDropOnItemIndex since we can’t provide multiple indexes.
+		guard let dropTargetNode = ancestorThatCanAcceptLocalFeed(parentNode) else {
+			return SidebarOutlineDataSource.dragOperationNone
+		}
+		if nodeHasChildRepresentingAnyDraggedFeed(dropTargetNode, draggedFeeds) {
+			return SidebarOutlineDataSource.dragOperationNone
+		}
+		if parentNode !== dropTargetNode || index != NSOutlineViewDropOnItemIndex {
+			outlineView.setDropItem(dropTargetNode, dropChildIndex: NSOutlineViewDropOnItemIndex)
+		}
+		return .move
+	}
+
 	func nodeIsAccountOrFolder(_ node: Node) -> Bool {
 		return node.representedObject is Account || node.representedObject is Folder
 	}
 
 	func nodeIsDropTarget(_ node: Node) -> Bool {
 		return node.canHaveChildNodes && nodeIsAccountOrFolder(node)
+	}
+
+	func ancestorThatCanAcceptLocalFeed(_ node: Node) -> Node? {
+		if nodeIsDropTarget(node) {
+			return node
+		}
+		guard let parentNode = node.parent else {
+			return nil
+		}
+		return ancestorThatCanAcceptLocalFeed(parentNode)
 	}
 
 	func ancestorThatCanAcceptNonLocalFeed(_ node: Node) -> Node? {

		return feed.isLocalFeed ? nil : feed
	}

	func validateLocalDrop(_ draggedFeeds: Set<PasteboardFeed>, parentNode: Node, proposedChildIndex index: Int) -> NSDragOperation {

//		let parentNode = nodeForItem(item)

		return SidebarOutlineDataSource.dragOperationNone
	}

	func validateSingleNonLocalFeedDrop(_ outlineView: NSOutlineView, _ draggedFeed: PasteboardFeed, _ parentNode: Node, _ index: Int) -> NSDragOperation {
		// A non-local feed should always drag on to an Account or Folder node, with NSOutlineViewDropOnItemIndex — since we don’t know where it would sort till we read the feed.
		guard let dropTargetNode = ancestorThatCanAcceptNonLocalFeed(parentNode) else {

		appDelegate.addFeed(draggedFeed.url, name: draggedFeed.editedName ?? draggedFeed.name, folder: folder)
		return true
	}

	func nodeHasChildRepresentingDraggedFeed(_ parentNode: Node, _ draggedFeed: PasteboardFeed) -> Bool {
		return nodeHasChildRepresentingAnyDraggedFeed(parentNode, Set([draggedFeed]))
	}

	func nodeRepresentsAnyDraggedFeed(_ node: Node, _ draggedFeeds: Set<PasteboardFeed>) -> Bool {
		guard let feed = node.representedObject as? Feed else {
			return false
		}
		for draggedFeed in draggedFeeds {
			if feed.url == draggedFeed.url {
				return true
			}
		}
		return false
	}

	func nodeHasChildRepresentingAnyDraggedFeed(_ parentNode: Node, _ draggedFeeds: Set<PasteboardFeed>) -> Bool {
		for node in parentNode.childNodes {
			if nodeRepresentsAnyDraggedFeed(node, draggedFeeds) {
				return true
			}
		}
		return false
	}

	func indexWhereDraggedFeedWouldAppear(_ parentNode: Node, _ draggedFeed: PasteboardFeed) -> Int {
		let draggedFeedWrapper = PasteboardFeedObjectWrapper(pasteboardFeed: draggedFeed)
		let draggedFeedNode = Node(representedObject: draggedFeedWrapper, parent: nil)
		let nodes = parentNode.childNodes + [draggedFeedNode]

		// Revisit if the tree controller can ever be sorted in some other way.
		let sortedNodes = nodes.sortedAlphabeticallyWithFoldersAtEnd()
		let index = sortedNodes.firstIndex(of: draggedFeedNode)!
		return index
	}
}

final class PasteboardFeedObjectWrapper: DisplayNameProvider {

	var nameForDisplay: String {
		return pasteboardFeed.editedName ?? pasteboardFeed.name ?? ""
	}
	let pasteboardFeed: PasteboardFeed

	init(pasteboardFeed: PasteboardFeed) {
		self.pasteboardFeed = pasteboardFeed
	}
}
