import Foundation /// Emoji reactions on a post in a thread. public struct OrgSocialMood: Sendable, Equatable { public let emoji: String public let posts: [String] public init(emoji: String, posts: [String]) { self.emoji = emoji self.posts = posts } } /// A node in the reply tree: a fully-resolved post plus its nested children. public struct OrgSocialThreadNode: Sendable { public let post: OrgSocialPost public let children: [OrgSocialThreadNode] public let moods: [OrgSocialMood] public init(post: OrgSocialPost, children: [OrgSocialThreadNode] = [], moods: [OrgSocialMood] = []) { self.post = post self.children = children self.moods = moods } } /// A fully-resolved conversation thread. public struct OrgSocialThread: Sendable { /// The post the thread was opened from. public let focalPost: OrgSocialPost /// Ancestor posts, oldest first (may be empty). public let parentChain: [OrgSocialPost] /// Direct replies to the focal post, each with their own nested children. public let replies: [OrgSocialThreadNode] /// Emoji reactions on the focal post. public let moods: [OrgSocialMood] public init( focalPost: OrgSocialPost, parentChain: [OrgSocialPost] = [], replies: [OrgSocialThreadNode] = [], moods: [OrgSocialMood] = [] ) { self.focalPost = focalPost self.parentChain = parentChain self.replies = replies self.moods = moods } /// Total number of replies (all depths combined). public var replyCount: Int { replies.reduce(0) { $0 + 1 + countChildren($1) } } private func countChildren(_ node: OrgSocialThreadNode) -> Int { node.children.reduce(0) { $0 + 1 + countChildren($1) } } } /// Interaction summary for a post (from /interactions/). public struct OrgSocialInteractions: Sendable { public let replyCount: Int public let reactionCount: Int public let boostCount: Int public let replyURLs: [String] /// Post URLs of the boost posts (one per booster). The feed URL of each /// booster is the prefix before `#` — useful for cross-checking "did I /// boost this?" without refetching the user's own feed. public let boostURLs: [String] /// Emoji reactions grouped by emoji, sorted by count descending. public let reactions: [OrgSocialMood] public init( replyCount: Int, reactionCount: Int, boostCount: Int, replyURLs: [String], boostURLs: [String] = [], reactions: [OrgSocialMood] = [] ) { self.replyCount = replyCount self.reactionCount = reactionCount self.boostCount = boostCount self.replyURLs = replyURLs self.boostURLs = boostURLs self.reactions = reactions } public var hasActivity: Bool { replyCount > 0 || reactionCount > 0 || boostCount > 0 } }