package isphere import "math" const reconciliationMediumTimestampWindowMillis int64 = 3000 type MessageReconciliationCandidate struct { Source string MessageID string ConversationID string SenderID string TimestampUnixMilli int64 BodyPresent bool AttachmentPresent bool } type MessageReconciliationSummary struct { LeftCount int RightCount int StrongMatches int MediumMatches int UnmatchedLeft int UnmatchedRight int AutoMergeRecommended bool } func ReconcileMessageSources(left, right []MessageReconciliationCandidate) MessageReconciliationSummary { matchedLeft := make([]bool, len(left)) matchedRight := make([]bool, len(right)) summary := MessageReconciliationSummary{LeftCount: len(left), RightCount: len(right)} for leftIndex, leftCandidate := range left { if leftCandidate.MessageID == "" { continue } for rightIndex, rightCandidate := range right { if matchedRight[rightIndex] || rightCandidate.MessageID == "" { continue } if leftCandidate.MessageID == rightCandidate.MessageID { matchedLeft[leftIndex] = true matchedRight[rightIndex] = true summary.StrongMatches++ break } } } for leftIndex, leftCandidate := range left { if matchedLeft[leftIndex] { continue } for rightIndex, rightCandidate := range right { if matchedRight[rightIndex] { continue } if isMediumMessageMatch(leftCandidate, rightCandidate) { matchedLeft[leftIndex] = true matchedRight[rightIndex] = true summary.MediumMatches++ break } } } summary.UnmatchedLeft = countFalse(matchedLeft) summary.UnmatchedRight = countFalse(matchedRight) summary.AutoMergeRecommended = shouldRecommendAutoMerge(summary) return summary } func isMediumMessageMatch(left, right MessageReconciliationCandidate) bool { if left.ConversationID == "" || right.ConversationID == "" || left.ConversationID != right.ConversationID { return false } if left.SenderID == "" || right.SenderID == "" || left.SenderID != right.SenderID { return false } if left.TimestampUnixMilli <= 0 || right.TimestampUnixMilli <= 0 { return false } delta := int64(math.Abs(float64(left.TimestampUnixMilli - right.TimestampUnixMilli))) return delta <= reconciliationMediumTimestampWindowMillis } func countFalse(values []bool) int { count := 0 for _, value := range values { if !value { count++ } } return count } func shouldRecommendAutoMerge(summary MessageReconciliationSummary) bool { if summary.LeftCount == 0 || summary.RightCount == 0 { return false } if summary.UnmatchedLeft != 0 || summary.UnmatchedRight != 0 || summary.MediumMatches != 0 { return false } return summary.StrongMatches == summary.LeftCount && summary.StrongMatches == summary.RightCount }