import Foundation enum TitleAnalysisEngine { static func analyze(title: String, goal: TitleGoal) -> TitleAnalysis { let length = title.count let lengthScore = scoreLength(length) let engagementScore = scoreEngagement(title, goal: goal) let clarityScore = scoreClarity(title) let overall = (lengthScore + engagementScore + clarityScore) / 3 let suggestions = makeSuggestions(title: title, length: length, goal: goal) return TitleAnalysis( overallScore: overall, lengthScore: lengthScore, engagementScore: engagementScore, clarityScore: clarityScore, suggestions: suggestions ) } private static func scoreLength(_ length: Int) -> Int { switch length { case 0: 0 case 1...50: 95 case 51...80: 85 case 81...120: 70 case 121...200: 50 case 201...300: 30 default: 10 } } private static func scoreEngagement(_ title: String, goal: TitleGoal) -> Int { var score = 50 let lower = title.lowercased() if title.contains("?") { score += 10 } if title.range(of: #"\d+"#, options: .regularExpression) != nil { score += 8 } if lower.contains("how") || lower.contains("why") || lower.contains("what") { score += 6 } if lower.contains("you") || lower.contains("your") { score += 5 } if title == title.uppercased() && title.count > 5 { score -= 15 } switch goal { case .question where !title.contains("?"): score -= 10 case .listicle where title.range(of: #"\d+"#, options: .regularExpression) == nil: score -= 8 case .curiosity where !lower.contains("secret") && !lower.contains("nobody") && !lower.contains("actually"): score -= 3 default: break } return min(100, max(0, score)) } private static func scoreClarity(_ title: String) -> Int { var score = 70 let words = title.split(separator: " ").count if words >= 4 && words <= 12 { score += 15 } if words < 3 { score -= 20 } if words > 20 { score -= 15 } if title.contains(" ") { score -= 5 } if title.hasPrefix(" ") || title.hasSuffix(" ") { score -= 10 } return min(100, max(0, score)) } private static func makeSuggestions(title: String, length: Int, goal: TitleGoal) -> [String] { var tips: [String] = [] if length > 120 { tips.append("Shorten to under 80 characters for better mobile visibility.") } else if length < 20 { tips.append("Add more context — very short titles can feel vague in feeds.") } if !title.contains("?") && goal == .question { tips.append("Reframe as a question to invite comments.") } if title.range(of: #"\d+"#, options: .regularExpression) == nil && goal == .listicle { tips.append("Include a number (e.g. \"5 tips\") for listicle-style engagement.") } let lower = title.lowercased() if goal == .curiosity && !lower.contains("?") { tips.append("Add a curiosity hook — hint at a surprising outcome.") } if tips.isEmpty { tips.append("Strong base title — try variants with different hooks below.") } return tips } }