package discovery import ( "strings" ) // suggestableProfilesSQL filters profiles that only have a bare email address. const suggestableProfilesSQL = ` AND ( EXISTS ( SELECT 1 FROM contact_discovered_signatures s WHERE s.profile_id = p.id ) OR ( COALESCE(trim(p.display_name), '') != '' AND p.display_name NOT ILIKE '%@%' AND lower(trim(p.display_name)) != lower(split_part(p.primary_email, '@', 1)) ) OR ( p.enriched_data IS NOT NULL AND ( nullif(trim(p.enriched_data->>'first_name'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'last_name'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'company'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'department'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'job_title'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'website'), '') IS NOT NULL OR nullif(trim(p.enriched_data->>'notes'), '') IS NOT NULL OR jsonb_array_length(COALESCE(p.enriched_data->'social_profiles', '[]'::jsonb)) > 0 OR jsonb_array_length(COALESCE(p.enriched_data->'phones', '[]'::jsonb)) > 0 OR jsonb_array_length(COALESCE(p.enriched_data->'addresses', '[]'::jsonb)) > 0 ) ) OR EXISTS ( SELECT 1 FROM jsonb_array_elements(COALESCE(p.all_emails, '[]'::jsonb)) AS e WHERE nullif(trim(e->>'display_name'), '') IS NOT NULL AND (e->>'display_name') NOT ILIKE '%@%' AND lower(trim(e->>'display_name')) != lower(split_part(COALESCE(e->>'email', ''), '@', 1)) ) )` func hasMeaningfulDisplayName(name, email string) bool { name = strings.TrimSpace(name) if name == "" || strings.Contains(name, "@") { return false } local := emailLocalPart(email) if local == "" { return true } return strings.ToLower(name) != local } func emailLocalPart(email string) string { email = strings.TrimSpace(email) at := strings.LastIndex(email, "@") if at <= 0 { return strings.ToLower(email) } return strings.ToLower(email[:at]) } func enrichedDataHasValueBeyondEmail(data *EnrichedContactData) bool { if data == nil { return false } if strings.TrimSpace(data.FirstName) != "" || strings.TrimSpace(data.LastName) != "" || strings.TrimSpace(data.Company) != "" || strings.TrimSpace(data.Department) != "" || strings.TrimSpace(data.JobTitle) != "" || strings.TrimSpace(data.Website) != "" || strings.TrimSpace(data.Notes) != "" { return true } for _, sp := range data.SocialProfiles { if strings.TrimSpace(sp.Value) != "" { return true } } for _, p := range data.Phones { if strings.TrimSpace(p.Value) != "" { return true } } for _, a := range data.Addresses { if strings.TrimSpace(a.Street) != "" || strings.TrimSpace(a.City) != "" || strings.TrimSpace(a.Region) != "" || strings.TrimSpace(a.PostalCode) != "" || strings.TrimSpace(a.Country) != "" { return true } } return false } // ProfileHasValueBeyondEmail reports whether a profile has contact info beyond a bare email. func ProfileHasValueBeyondEmail(p Profile) bool { if len(p.Signatures) > 0 { return true } if enrichedDataHasValueBeyondEmail(p.EnrichedData) { return true } if hasMeaningfulDisplayName(p.DisplayName, p.PrimaryEmail) { return true } for _, e := range p.AllEmails { if hasMeaningfulDisplayName(e.DisplayName, e.Email) { return true } } return false } func profileGroupHasValueBeyondEmail(group ProfileGroup) bool { for _, p := range group.Profiles { if ProfileHasValueBeyondEmail(p) { return true } } return ProfileHasValueBeyondEmail(group.Profile) } func profileHasNoReplyEmail(p Profile) bool { if isNoReplyEmail(p.PrimaryEmail) { return true } for _, e := range p.AllEmails { if isNoReplyEmail(e.Email) { return true } } if p.EnrichedData != nil { for _, e := range p.EnrichedData.Emails { if isNoReplyEmail(e.Value) { return true } } } return false } func profileGroupHasNoReplyEmail(group ProfileGroup) bool { for _, p := range group.Profiles { if profileHasNoReplyEmail(p) { return true } } return profileHasNoReplyEmail(group.Profile) } func filterSuggestableGroups(groups []ProfileGroup) []ProfileGroup { if len(groups) == 0 { return groups } out := make([]ProfileGroup, 0, len(groups)) for _, g := range groups { if profileGroupHasNoReplyEmail(g) { continue } if profileGroupHasValueBeyondEmail(g) { out = append(out, g) } } return out }