// Match scoring engine for discovered profiles const DEFAULT_WEIGHTS = { verification: 15, photoBase: 2, // per photo (max 6) photoVerified: 3, // per verified photo bioLong: 15, // >200 chars bioMedium: 10, // >100 chars bioShort: 5, // >30 chars desiresMany: 8, // >=5 desires desiresSome: 5, // >=3 desires connectionGoals: 5, // has any distanceClose: 15, // <=15mi distanceMedium: 10, // <=30mi distanceFar: 5, // <=50mi ageSweetSpot: 15, // 24-40 (preferred) ageOk: 5, // 21-45 ageOutOfRange: -10, // outside 21-45 penalty theyLikedYou: 30, // interactionStatus.theirs === 'LIKED' connectionDesires: 5, // >=2 of CONNECTION/COMMUNICATION/FWB/INTIMACY/RELATIONSHIP }; const CONNECTION_DESIRE_KEYWORDS = [ 'CONNECTION', 'COMMUNICATION', 'FWB', 'INTIMACY', 'RELATIONSHIP', 'connection', 'communication', 'fwb', 'intimacy', 'relationship', 'Friends with benefits', 'Long-term relationship', 'Short-term relationship', ]; function safeStr(v) { return typeof v === 'string' ? v : ''; } function scoreProfile(profile, weights = DEFAULT_WEIGHTS) { const breakdown = {}; let total = 0; // Verification const verStatus = safeStr(profile.verificationStatus); if (verStatus === 'VERIFIED' || verStatus === 'verified') { breakdown.verification = weights.verification; total += weights.verification; } // Photos const photos = Array.isArray(profile.photos) ? profile.photos : []; const photoCount = Math.min(photos.length, 6); if (photoCount > 0) { const photoScore = photoCount * weights.photoBase; breakdown.photos = photoScore; total += photoScore; } // Verified photos (pictureType === 'VERIFIED' or similar) const verifiedPhotos = photos.filter(p => p.pictureType === 'VERIFIED' || p.pictureType === 'verified' ).length; if (verifiedPhotos > 0) { const vpScore = verifiedPhotos * weights.photoVerified; breakdown.verifiedPhotos = vpScore; total += vpScore; } // Bio quality const bio = safeStr(profile.bio); if (bio.length > 200) { breakdown.bio = weights.bioLong; total += weights.bioLong; } else if (bio.length > 100) { breakdown.bio = weights.bioMedium; total += weights.bioMedium; } else if (bio.length > 30) { breakdown.bio = weights.bioShort; total += weights.bioShort; } // Desires const desires = Array.isArray(profile.desires) ? profile.desires : []; if (desires.length >= 5) { breakdown.desires = weights.desiresMany; total += weights.desiresMany; } else if (desires.length >= 3) { breakdown.desires = weights.desiresSome; total += weights.desiresSome; } // Connection goals const goals = Array.isArray(profile.connectionGoals) ? profile.connectionGoals : []; if (goals.length > 0) { breakdown.connectionGoals = weights.connectionGoals; total += weights.connectionGoals; } // Distance const distMi = profile.distance?.mi; if (typeof distMi === 'number') { if (distMi <= 15) { breakdown.distance = weights.distanceClose; total += weights.distanceClose; } else if (distMi <= 30) { breakdown.distance = weights.distanceMedium; total += weights.distanceMedium; } else if (distMi <= 50) { breakdown.distance = weights.distanceFar; total += weights.distanceFar; } } // Age preference: 24-40 sweet spot, 21-45 ok, outside penalized const age = profile.age; if (typeof age === 'number') { if (age >= 24 && age <= 40) { breakdown.age = weights.ageSweetSpot; total += weights.ageSweetSpot; } else if (age >= 21 && age <= 45) { breakdown.age = weights.ageOk; total += weights.ageOk; } else { breakdown.age = weights.ageOutOfRange; total += weights.ageOutOfRange; } } // They liked you if (profile.interactionStatus?.theirs === 'LIKED') { breakdown.theyLikedYou = weights.theyLikedYou; total += weights.theyLikedYou; } // Connection desires (check desires array for relationship-oriented ones) const desireStrings = desires.map(d => typeof d === 'string' ? d : ''); const matchingDesires = desireStrings.filter(d => CONNECTION_DESIRE_KEYWORDS.some(kw => d.toUpperCase().includes(kw.toUpperCase())) ); if (matchingDesires.length >= 2) { breakdown.connectionDesires = weights.connectionDesires; total += weights.connectionDesires; } return { total, breakdown }; } export { DEFAULT_WEIGHTS, scoreProfile, safeStr };