package formatter import ( "encoding/json" "fmt" "strings" "git.db.org.ai/dborg/internal/models" ) func FormatNPDResults(resp *models.NPDResponse, asJSON bool) (string, error) { if asJSON { data, err := json.MarshalIndent(resp.Results.Hits, "", " ") if err != nil { return "", fmt.Errorf("failed to marshal JSON: %w", err) } return string(data), nil } var sb strings.Builder sb.WriteString(fmt.Sprintf("\n%s\n", Bold(Cyan("NPD Breach Data Search Results")))) sb.WriteString(fmt.Sprintf("%s\n\n", Gray(strings.Repeat("─", 50)))) sb.WriteString(fmt.Sprintf("%s %s / %s max\n", Blue("Total Hits:"), Yellow(fmt.Sprintf("%d", resp.Results.NumHits)), Dim(fmt.Sprintf("%d", resp.MaxHits)))) sb.WriteString(fmt.Sprintf("%s %s\n\n", Blue("Query Time:"), Dim(fmt.Sprintf("%d microseconds", resp.Results.ElapsedTimeMicros)))) if len(resp.Results.Errors) > 0 { sb.WriteString(fmt.Sprintf("%s\n", Red("Errors:"))) for _, err := range resp.Results.Errors { sb.WriteString(fmt.Sprintf(" %s %s\n", Red("✗"), err)) } sb.WriteString("\n") } if len(resp.Results.Hits) > 0 { sb.WriteString(fmt.Sprintf("%s\n", Bold("Records:"))) sb.WriteString(fmt.Sprintf("%s\n", Gray(strings.Repeat("─", 50)))) for i, hit := range resp.Results.Hits { sb.WriteString(fmt.Sprintf("\n%s:\n", Bold(Blue(fmt.Sprintf("Record %d", i+1))))) if name := getStringField(hit, "firstname", "lastname", "middlename"); name != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("Name:"), Bold(name))) } if dob := getStringField(hit, "dob"); dob != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("DOB:"), dob)) } if ssn := getStringField(hit, "ssn"); ssn != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("SSN:"), Yellow(ssn))) } if phone := getStringField(hit, "phone1"); phone != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("Phone:"), phone)) } if addr := buildAddress(hit); addr != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("Address:"), addr)) } for k, v := range hit { if !isCommonField(k) && v != nil && v != "" { sb.WriteString(fmt.Sprintf(" %s %v\n", Dim(fmt.Sprintf("%s:", k)), v)) } } } } else { sb.WriteString(fmt.Sprintf("%s\n", Gray("No records found"))) } sb.WriteString("\n") if resp.Credits.Unlimited { sb.WriteString(fmt.Sprintf("%s: %s\n", Dim("Credits"), Green("Unlimited"))) } else { sb.WriteString(fmt.Sprintf("%s: %s\n", Dim("Credits Remaining"), FormatCredits(int64(resp.Credits.Remaining)))) } return sb.String(), nil } func getStringField(data map[string]any, keys ...string) string { var parts []string for _, key := range keys { if val, ok := data[key]; ok && val != nil { if str, ok := val.(string); ok && str != "" { parts = append(parts, str) } } } return strings.Join(parts, " ") } func buildAddress(data map[string]any) string { var parts []string if addr, ok := data["address"].(string); ok && addr != "" { parts = append(parts, addr) } cityStateZip := []string{} if city, ok := data["city"].(string); ok && city != "" { cityStateZip = append(cityStateZip, city) } if state, ok := data["st"].(string); ok && state != "" { cityStateZip = append(cityStateZip, state) } if zip, ok := data["zip"].(string); ok && zip != "" { cityStateZip = append(cityStateZip, zip) } if len(cityStateZip) > 0 { parts = append(parts, strings.Join(cityStateZip, ", ")) } return strings.Join(parts, ", ") } func isCommonField(field string) bool { commonFields := map[string]bool{ "firstname": true, "lastname": true, "middlename": true, "dob": true, "ssn": true, "phone1": true, "address": true, "city": true, "st": true, "zip": true, } return commonFields[field] }