package formatter import ( "fmt" "strings" "git.db.org.ai/dborg/internal/models" "github.com/charmbracelet/lipgloss" ) func FormatSkiptraceResults(resp interface{}, asJSON bool) (string, error) { var data map[string]interface{} switch r := resp.(type) { case *models.SkiptraceResponse: data = r.Data case *models.SkiptraceReportResponse: data = r.Data case *models.SkiptracePhoneResponse: data = r.Data case *models.SkiptraceEmailResponse: data = r.Data default: return "", fmt.Errorf("unsupported skiptrace response type") } err := PrintColorizedJSON(data) if err != nil { return "", fmt.Errorf("failed to marshal JSON: %w", err) } return "", nil } func formatSkiptraceData(sb *strings.Builder, data map[string]interface{}) { if person, ok := data["person"].(map[string]interface{}); ok { sb.WriteString(fmt.Sprintf("%s\n", Bold("Person Information:"))) formatPersonInfo(sb, person) delete(data, "person") } if phones, ok := data["phones"].([]interface{}); ok && len(phones) > 0 { sb.WriteString(fmt.Sprintf("\n%s\n", Bold("Phone Numbers:"))) for _, phone := range phones { if phoneMap, ok := phone.(map[string]interface{}); ok { if number, ok := phoneMap["number"].(string); ok { sb.WriteString(fmt.Sprintf(" %s %s", Dim("•"), Cyan(number))) if carrier, ok := phoneMap["carrier"].(string); ok && carrier != "" { sb.WriteString(fmt.Sprintf(" %s", Gray(fmt.Sprintf("(%s)", carrier)))) } if phoneType, ok := phoneMap["type"].(string); ok && phoneType != "" { sb.WriteString(fmt.Sprintf(" %s", Dim(phoneType))) } sb.WriteString("\n") } } } delete(data, "phones") } if emails, ok := data["emails"].([]interface{}); ok && len(emails) > 0 { sb.WriteString(fmt.Sprintf("\n%s\n", Bold("Email Addresses:"))) for _, email := range emails { if emailStr, ok := email.(string); ok { sb.WriteString(fmt.Sprintf(" %s %s\n", Dim("•"), Blue(emailStr))) } } delete(data, "emails") } if addresses, ok := data["addresses"].([]interface{}); ok && len(addresses) > 0 { sb.WriteString(fmt.Sprintf("\n%s\n", Bold("Addresses:"))) for _, addr := range addresses { if addrMap, ok := addr.(map[string]interface{}); ok { formatAddress(sb, addrMap) } } delete(data, "addresses") } if len(data) > 0 { sb.WriteString(fmt.Sprintf("\n%s\n", Bold("Additional Information:"))) if colorized, err := FormatColorizedJSON(data); err == nil { lines := strings.Split(colorized, "\n") for _, line := range lines { sb.WriteString(fmt.Sprintf(" %s\n", line)) } } } } func formatPersonInfo(sb *strings.Builder, person map[string]interface{}) { if name, ok := person["name"].(string); ok && name != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("Name:"), Bold(name))) } if age, ok := person["age"].(float64); ok && age > 0 { sb.WriteString(fmt.Sprintf(" %s %d\n", Cyan("Age:"), int(age))) } if dob, ok := person["dob"].(string); ok && dob != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", Cyan("DOB:"), dob)) } } func formatAddress(sb *strings.Builder, addr map[string]interface{}) { var addrStr strings.Builder if street, ok := addr["street"].(string); ok && street != "" { addrStr.WriteString(street) } if city, ok := addr["city"].(string); ok && city != "" { if addrStr.Len() > 0 { addrStr.WriteString(", ") } addrStr.WriteString(city) } if state, ok := addr["state"].(string); ok && state != "" { if addrStr.Len() > 0 { addrStr.WriteString(", ") } addrStr.WriteString(state) } if zip, ok := addr["zip"].(string); ok && zip != "" { if addrStr.Len() > 0 { addrStr.WriteString(" ") } addrStr.WriteString(zip) } if addrStr.Len() > 0 { sb.WriteString(fmt.Sprintf(" %s %s\n", Dim("•"), addrStr.String())) } } var ( reportTitleStyle = lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("86")). MarginBottom(1) reportSectionStyle = lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("212")). MarginTop(1) reportSubsectionStyle = lipgloss.NewStyle(). Bold(true). Foreground(lipgloss.Color("229")) reportLabelStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("117")) reportValueStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("252")) reportDimStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("243")) reportHighlightStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("156")) reportWarningStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("214")) reportDividerStyle = lipgloss.NewStyle(). Foreground(lipgloss.Color("240")) ) func FormatSkiptraceReport(data map[string]interface{}) string { var sb strings.Builder sb.WriteString(reportTitleStyle.Render("━━━ SKIPTRACE REPORT ━━━")) sb.WriteString("\n\n") formatReportBasicInfo(&sb, data) formatReportGender(&sb, data) formatReportNames(&sb, data) formatReportDOB(&sb, data) formatReportUsernames(&sb, data) formatReportAddresses(&sb, data) formatReportPhones(&sb, data) formatReportEmails(&sb, data) formatReportURLs(&sb, data) formatReportOtherProfiles(&sb, data) formatReportAssociates(&sb, data) formatReportRelatives(&sb, data) formatReportRelatedPersons(&sb, data) formatReportPossibleAssociates(&sb, data) formatReportEmployment(&sb, data) formatReportEducation(&sb, data) formatReportProperties(&sb, data) formatReportVehicles(&sb, data) formatReportCriminalRecords(&sb, data) formatReportVoterRecords(&sb, data) formatReportSocialProfiles(&sb, data) formatReportImages(&sb, data) formatReportTags(&sb, data) sb.WriteString("\n") sb.WriteString(reportDividerStyle.Render(strings.Repeat("━", 50))) sb.WriteString("\n") return sb.String() } func formatReportBasicInfo(sb *strings.Builder, data map[string]interface{}) { if person, ok := data["person"].(map[string]interface{}); ok { sb.WriteString(reportSectionStyle.Render("▸ BASIC INFORMATION")) sb.WriteString("\n") if name, ok := person["name"].(string); ok && name != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Name:"), reportValueStyle.Render(name))) } if gender, ok := person["gender"].(string); ok && gender != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Gender:"), reportValueStyle.Render(gender))) } sb.WriteString("\n") } } func formatReportGender(sb *strings.Builder, data map[string]interface{}) { gender, ok := data["gender"].(map[string]interface{}) if !ok { return } content, ok := gender["content"].(string) if !ok || content == "" { return } sb.WriteString(reportSectionStyle.Render("▸ GENDER")) sb.WriteString("\n") sb.WriteString(fmt.Sprintf(" %s %s\n\n", reportLabelStyle.Render("Gender:"), reportValueStyle.Render(content))) } func formatReportNames(sb *strings.Builder, data map[string]interface{}) { names, ok := data["names"].([]interface{}) if !ok || len(names) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ NAMES / ALIASES")) sb.WriteString("\n") for _, n := range names { nameMap, ok := n.(map[string]interface{}) if !ok { continue } var nameParts []string if first, ok := nameMap["first"].(string); ok && first != "" { nameParts = append(nameParts, first) } if middle, ok := nameMap["middle"].(string); ok && middle != "" { nameParts = append(nameParts, middle) } if last, ok := nameMap["last"].(string); ok && last != "" { nameParts = append(nameParts, last) } if display, ok := nameMap["display"].(string); ok && display != "" { nameParts = []string{display} } if len(nameParts) > 0 { nameStr := strings.Join(nameParts, " ") typeStr := "" if nameType, ok := nameMap["type"].(string); ok && nameType != "" { typeStr = reportDimStyle.Render(fmt.Sprintf(" (%s)", nameType)) } sb.WriteString(fmt.Sprintf(" %s %s%s\n", reportDimStyle.Render("•"), reportValueStyle.Render(nameStr), typeStr)) } } sb.WriteString("\n") } func formatReportDOB(sb *strings.Builder, data map[string]interface{}) { dob, ok := data["dob"].(map[string]interface{}) if !ok { if dobStr, ok := data["dob"].(string); ok && dobStr != "" { sb.WriteString(reportSectionStyle.Render("▸ DATE OF BIRTH")) sb.WriteString("\n") sb.WriteString(fmt.Sprintf(" %s %s\n\n", reportLabelStyle.Render("DOB:"), reportValueStyle.Render(dobStr))) } return } sb.WriteString(reportSectionStyle.Render("▸ DATE OF BIRTH")) sb.WriteString("\n") if display, ok := dob["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Date:"), reportValueStyle.Render(display))) } if age, ok := dob["age"].(float64); ok && age > 0 { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Age:"), reportValueStyle.Render(fmt.Sprintf("%d", int(age))))) } if zodiac, ok := dob["zodiac"].(string); ok && zodiac != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Zodiac:"), reportValueStyle.Render(zodiac))) } sb.WriteString("\n") } func formatReportUsernames(sb *strings.Builder, data map[string]interface{}) { usernames, ok := data["usernames"].([]interface{}) if !ok || len(usernames) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ USERNAMES")) sb.WriteString("\n") for _, u := range usernames { if username, ok := u.(string); ok && username != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportHighlightStyle.Render(username))) } else if usernameMap, ok := u.(map[string]interface{}); ok { if name, ok := usernameMap["username"].(string); ok && name != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(name))) if source, ok := usernameMap["source"].(string); ok && source != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", source))) } sb.WriteString("\n") } } } sb.WriteString("\n") } func formatReportAddresses(sb *strings.Builder, data map[string]interface{}) { addresses, ok := data["addresses"].([]interface{}) if !ok || len(addresses) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ ADDRESSES")) sb.WriteString("\n") var current, historical []map[string]interface{} for _, a := range addresses { addrMap, ok := a.(map[string]interface{}) if !ok { continue } if isCurrent, ok := addrMap["current"].(bool); ok && isCurrent { current = append(current, addrMap) } else { historical = append(historical, addrMap) } } if len(current) > 0 { sb.WriteString(reportSubsectionStyle.Render(" Current:")) sb.WriteString("\n") for _, addr := range current { formatReportAddress(sb, addr, " ") } } if len(historical) > 0 { sb.WriteString(reportSubsectionStyle.Render(" Historical:")) sb.WriteString("\n") for i, addr := range historical { if i >= 5 { sb.WriteString(fmt.Sprintf(" %s\n", reportDimStyle.Render(fmt.Sprintf("... and %d more", len(historical)-5)))) break } formatReportAddress(sb, addr, " ") } } sb.WriteString("\n") } func formatReportAddress(sb *strings.Builder, addr map[string]interface{}, indent string) { if display, ok := addr["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf("%s%s %s", indent, reportDimStyle.Render("•"), reportValueStyle.Render(display))) } else { var parts []string if street, ok := addr["street"].(string); ok && street != "" { parts = append(parts, street) } if city, ok := addr["city"].(string); ok && city != "" { parts = append(parts, city) } if state, ok := addr["state"].(string); ok && state != "" { parts = append(parts, state) } if zip, ok := addr["zip"].(string); ok && zip != "" { parts = append(parts, zip) } if len(parts) > 0 { sb.WriteString(fmt.Sprintf("%s%s %s", indent, reportDimStyle.Render("•"), reportValueStyle.Render(strings.Join(parts, ", ")))) } } var meta []string if addrType, ok := addr["type"].(string); ok && addrType != "" { meta = append(meta, addrType) } if firstSeen, ok := addr["first_seen"].(string); ok && firstSeen != "" { meta = append(meta, fmt.Sprintf("since %s", firstSeen)) } if lastSeen, ok := addr["last_seen"].(string); ok && lastSeen != "" { meta = append(meta, fmt.Sprintf("until %s", lastSeen)) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", strings.Join(meta, ", ")))) } sb.WriteString("\n") detailIndent := indent + " " if county, ok := addr["county"].(string); ok && county != "" { sb.WriteString(fmt.Sprintf("%s%s %s\n", detailIndent, reportDimStyle.Render("County:"), reportValueStyle.Render(county))) } hasCoords := false var lat, lon float64 if l, ok := addr["latitude"].(float64); ok { lat = l hasCoords = true } if l, ok := addr["longitude"].(float64); ok { lon = l hasCoords = hasCoords && true } if hasCoords && (lat != 0 || lon != 0) { sb.WriteString(fmt.Sprintf("%s%s %.6f, %.6f\n", detailIndent, reportDimStyle.Render("Coords:"), lat, lon)) } if countyFips, ok := addr["county_fips"].(string); ok && countyFips != "" { sb.WriteString(fmt.Sprintf("%s%s %s\n", detailIndent, reportDimStyle.Render("FIPS:"), reportValueStyle.Render(countyFips))) } if congDistrict, ok := addr["congressional_district"].(string); ok && congDistrict != "" { sb.WriteString(fmt.Sprintf("%s%s %s\n", detailIndent, reportDimStyle.Render("Congressional District:"), reportValueStyle.Render(congDistrict))) } } func formatReportPhones(sb *strings.Builder, data map[string]interface{}) { phones, ok := data["phones"].([]interface{}) if !ok || len(phones) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ PHONE NUMBERS")) sb.WriteString("\n") for _, p := range phones { phoneMap, ok := p.(map[string]interface{}) if !ok { continue } number := "" if display, ok := phoneMap["display"].(string); ok && display != "" { number = display } else if num, ok := phoneMap["number"].(string); ok && num != "" { number = num } if number == "" { continue } sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(number))) var meta []string if phoneType, ok := phoneMap["type"].(string); ok && phoneType != "" { meta = append(meta, phoneType) } if carrier, ok := phoneMap["carrier"].(string); ok && carrier != "" { meta = append(meta, carrier) } if lineType, ok := phoneMap["line_type"].(string); ok && lineType != "" { meta = append(meta, lineType) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", strings.Join(meta, ", ")))) } sb.WriteString("\n") } sb.WriteString("\n") } func formatReportEmails(sb *strings.Builder, data map[string]interface{}) { emails, ok := data["emails"].([]interface{}) if !ok || len(emails) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ EMAIL ADDRESSES")) sb.WriteString("\n") for _, e := range emails { switch email := e.(type) { case string: if email != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportHighlightStyle.Render(email))) } case map[string]interface{}: addr := "" if address, ok := email["address"].(string); ok && address != "" { addr = address } else if display, ok := email["display"].(string); ok && display != "" { addr = display } if addr != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(addr))) if emailType, ok := email["type"].(string); ok && emailType != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", emailType))) } sb.WriteString("\n") } } } sb.WriteString("\n") } func formatReportURLs(sb *strings.Builder, data map[string]interface{}) { urls, ok := data["urls"].([]interface{}) if !ok || len(urls) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ WEB PRESENCE")) sb.WriteString("\n") for _, u := range urls { switch url := u.(type) { case string: if url != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportHighlightStyle.Render(url))) } case map[string]interface{}: urlStr := "" if u, ok := url["url"].(string); ok && u != "" { urlStr = u } else if u, ok := url["@source_url"].(string); ok && u != "" { urlStr = u } if urlStr != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(urlStr))) if domain, ok := url["@domain"].(string); ok && domain != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", domain))) } else if name, ok := url["@name"].(string); ok && name != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", name))) } sb.WriteString("\n") } } } sb.WriteString("\n") } func formatReportOtherProfiles(sb *strings.Builder, data map[string]interface{}) { profiles, ok := data["otherProfiles"].([]interface{}) if !ok || len(profiles) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ OTHER PROFILES")) sb.WriteString("\n") for _, p := range profiles { profileMap, ok := p.(map[string]interface{}) if !ok { continue } url := "" if u, ok := profileMap["url"].(string); ok && u != "" { url = u } else if u, ok := profileMap["@source_url"].(string); ok && u != "" { url = u } if url != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(url))) var meta []string if name, ok := profileMap["@name"].(string); ok && name != "" { meta = append(meta, name) } if domain, ok := profileMap["@domain"].(string); ok && domain != "" { meta = append(meta, domain) } if category, ok := profileMap["@category"].(string); ok && category != "" { meta = append(meta, category) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", strings.Join(meta, ", ")))) } sb.WriteString("\n") } } sb.WriteString("\n") } func formatReportAssociates(sb *strings.Builder, data map[string]interface{}) { associates, ok := data["associates"].([]interface{}) if !ok || len(associates) == 0 { return } var lines []string for _, a := range associates { assocMap, ok := a.(map[string]interface{}) if !ok { continue } name := extractPersonName(assocMap) if name == "" { continue } line := fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(name)) if relation, ok := assocMap["relation"].(string); ok && relation != "" { line += reportDimStyle.Render(fmt.Sprintf(" (%s)", relation)) } else if relation, ok := assocMap["type"].(string); ok && relation != "" { line += reportDimStyle.Render(fmt.Sprintf(" (%s)", relation)) } lines = append(lines, line) } if len(lines) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ ASSOCIATES")) sb.WriteString("\n") for _, line := range lines { sb.WriteString(line + "\n") } sb.WriteString("\n") } func formatReportRelatives(sb *strings.Builder, data map[string]interface{}) { relatives, ok := data["relatives"].([]interface{}) if !ok || len(relatives) == 0 { relatives, ok = data["relationships"].([]interface{}) if !ok || len(relatives) == 0 { return } } var lines []string for _, r := range relatives { relMap, ok := r.(map[string]interface{}) if !ok { continue } name := extractPersonName(relMap) if name == "" { continue } line := fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(name)) if relation, ok := relMap["type"].(string); ok && relation != "" { line += reportDimStyle.Render(fmt.Sprintf(" (%s)", relation)) } else if relation, ok := relMap["relation"].(string); ok && relation != "" { line += reportDimStyle.Render(fmt.Sprintf(" (%s)", relation)) } lines = append(lines, line) } if len(lines) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ RELATIVES")) sb.WriteString("\n") for _, line := range lines { sb.WriteString(line + "\n") } sb.WriteString("\n") } func formatReportRelatedPersons(sb *strings.Builder, data map[string]interface{}) { relatedPersons, ok := data["related_persons"].([]interface{}) if !ok || len(relatedPersons) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ RELATED PERSONS")) sb.WriteString("\n") for _, rp := range relatedPersons { rpMap, ok := rp.(map[string]interface{}) if !ok { continue } name := extractPersonName(rpMap) if name == "" { continue } sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(name))) var meta []string if relation, ok := rpMap["@type"].(string); ok && relation != "" { meta = append(meta, relation) } else if relation, ok := rpMap["type"].(string); ok && relation != "" { meta = append(meta, relation) } if subtype, ok := rpMap["@subtype"].(string); ok && subtype != "" { meta = append(meta, subtype) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" (%s)", strings.Join(meta, " - ")))) } sb.WriteString("\n") if phones, ok := rpMap["phones"].([]interface{}); ok && len(phones) > 0 { for _, p := range phones { if phoneMap, ok := p.(map[string]interface{}); ok { if display, ok := phoneMap["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Phone:"), reportHighlightStyle.Render(display))) } } } } if emails, ok := rpMap["emails"].([]interface{}); ok && len(emails) > 0 { for _, e := range emails { if emailMap, ok := e.(map[string]interface{}); ok { if addr, ok := emailMap["address"].(string); ok && addr != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Email:"), reportHighlightStyle.Render(addr))) } } } } if addresses, ok := rpMap["addresses"].([]interface{}); ok && len(addresses) > 0 { if addrMap, ok := addresses[0].(map[string]interface{}); ok { if display, ok := addrMap["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Address:"), reportValueStyle.Render(display))) } } } } sb.WriteString("\n") } func formatReportPossibleAssociates(sb *strings.Builder, data map[string]interface{}) { associates, ok := data["possible_associates"].([]interface{}) if !ok || len(associates) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ POSSIBLE ASSOCIATES")) sb.WriteString("\n") for i, a := range associates { if i >= 10 { sb.WriteString(fmt.Sprintf(" %s\n", reportDimStyle.Render(fmt.Sprintf("... and %d more", len(associates)-10)))) break } assocMap, ok := a.(map[string]interface{}) if !ok { continue } name := extractPersonName(assocMap) if name == "" { continue } sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(name))) var meta []string if relation, ok := assocMap["@type"].(string); ok && relation != "" { meta = append(meta, relation) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" (%s)", strings.Join(meta, ", ")))) } sb.WriteString("\n") if addresses, ok := assocMap["addresses"].([]interface{}); ok && len(addresses) > 0 { if addrMap, ok := addresses[0].(map[string]interface{}); ok { if display, ok := addrMap["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Location:"), reportValueStyle.Render(display))) } } } if phones, ok := assocMap["phones"].([]interface{}); ok && len(phones) > 0 { if phoneMap, ok := phones[0].(map[string]interface{}); ok { if display, ok := phoneMap["display"].(string); ok && display != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Phone:"), reportHighlightStyle.Render(display))) } } } if emails, ok := assocMap["emails"].([]interface{}); ok && len(emails) > 0 { if emailMap, ok := emails[0].(map[string]interface{}); ok { if addr, ok := emailMap["address"].(string); ok && addr != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Email:"), reportHighlightStyle.Render(addr))) } } } } sb.WriteString("\n") } func extractPersonName(personMap map[string]interface{}) string { if display, ok := personMap["name"].(string); ok && display != "" { return display } if display, ok := personMap["display"].(string); ok && display != "" { return display } if names, ok := personMap["names"].([]interface{}); ok && len(names) > 0 { if nameMap, ok := names[0].(map[string]interface{}); ok { if display, ok := nameMap["display"].(string); ok && display != "" { return display } var parts []string if first, ok := nameMap["first"].(string); ok && first != "" { parts = append(parts, first) } if middle, ok := nameMap["middle"].(string); ok && middle != "" { parts = append(parts, middle) } if last, ok := nameMap["last"].(string); ok && last != "" { parts = append(parts, last) } if len(parts) > 0 { return strings.Join(parts, " ") } } } var parts []string if first, ok := personMap["first_name"].(string); ok && first != "" { parts = append(parts, first) } if last, ok := personMap["last_name"].(string); ok && last != "" { parts = append(parts, last) } if len(parts) > 0 { return strings.Join(parts, " ") } return "" } func formatReportEmployment(sb *strings.Builder, data map[string]interface{}) { jobs, ok := data["jobs"].([]interface{}) if !ok || len(jobs) == 0 { jobs, ok = data["employment"].([]interface{}) if !ok || len(jobs) == 0 { return } } sb.WriteString(reportSectionStyle.Render("▸ EMPLOYMENT")) sb.WriteString("\n") for _, j := range jobs { jobMap, ok := j.(map[string]interface{}) if !ok { continue } var parts []string if title, ok := jobMap["title"].(string); ok && title != "" { parts = append(parts, title) } if org, ok := jobMap["organization"].(string); ok && org != "" { parts = append(parts, fmt.Sprintf("at %s", org)) } else if company, ok := jobMap["company"].(string); ok && company != "" { parts = append(parts, fmt.Sprintf("at %s", company)) } if len(parts) > 0 { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(strings.Join(parts, " ")))) if dateRange, ok := jobMap["date_range"].(string); ok && dateRange != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", dateRange))) } sb.WriteString("\n") } } sb.WriteString("\n") } func formatReportEducation(sb *strings.Builder, data map[string]interface{}) { education, ok := data["educations"].([]interface{}) if !ok || len(education) == 0 { education, ok = data["education"].([]interface{}) if !ok || len(education) == 0 { return } } sb.WriteString(reportSectionStyle.Render("▸ EDUCATION")) sb.WriteString("\n") for _, e := range education { eduMap, ok := e.(map[string]interface{}) if !ok { continue } var parts []string if degree, ok := eduMap["degree"].(string); ok && degree != "" { parts = append(parts, degree) } if school, ok := eduMap["school"].(string); ok && school != "" { parts = append(parts, fmt.Sprintf("from %s", school)) } if len(parts) > 0 { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(strings.Join(parts, " ")))) if dateRange, ok := eduMap["date_range"].(string); ok && dateRange != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", dateRange))) } sb.WriteString("\n") } } sb.WriteString("\n") } func formatReportProperties(sb *strings.Builder, data map[string]interface{}) { current, hasCurrentProps := data["current_properties"].([]interface{}) past, hasPastProps := data["past_properties"].([]interface{}) all, hasAllProps := data["properties"].([]interface{}) hasValidCurrent := hasCurrentProps && len(current) > 0 && hasValidProperty(current) hasValidPast := hasPastProps && len(past) > 0 && hasValidProperty(past) hasValidAll := hasAllProps && len(all) > 0 && hasValidProperty(all) if !hasValidCurrent && !hasValidPast && !hasValidAll { return } sb.WriteString(reportSectionStyle.Render("▸ PROPERTIES")) sb.WriteString("\n") if hasValidCurrent { sb.WriteString(reportSubsectionStyle.Render(" Current Properties:")) sb.WriteString("\n") for _, p := range current { _ = formatReportProperty(sb, p, " ") } } if hasValidPast { sb.WriteString(reportSubsectionStyle.Render(" Past Properties:")) sb.WriteString("\n") count := 0 for _, p := range past { if count >= 3 { sb.WriteString(fmt.Sprintf(" %s\n", reportDimStyle.Render(fmt.Sprintf("... and %d more", len(past)-3)))) break } if formatReportProperty(sb, p, " ") { count++ } } } if hasValidAll && !hasValidCurrent && !hasValidPast { count := 0 for _, p := range all { if count >= 5 { sb.WriteString(fmt.Sprintf(" %s\n", reportDimStyle.Render(fmt.Sprintf("... and %d more", len(all)-5)))) break } if formatReportProperty(sb, p, " ") { count++ } } } sb.WriteString("\n") } func hasValidProperty(props []interface{}) bool { for _, p := range props { propMap, ok := p.(map[string]interface{}) if !ok { continue } if extractPropertyAddress(propMap) != "" { return true } } return false } func extractPropertyAddress(propMap map[string]interface{}) string { if addr, ok := propMap["address"].(string); ok && addr != "" { return addr } if addrMap, ok := propMap["address"].(map[string]interface{}); ok { if display, ok := addrMap["display"].(string); ok && display != "" { return display } return buildAddressFromParts(addrMap) } if display, ok := propMap["display"].(string); ok && display != "" { return display } return buildAddressFromParts(propMap) } func buildAddressFromParts(addrMap map[string]interface{}) string { var parts []string if street, ok := addrMap["street"].(string); ok && street != "" { parts = append(parts, street) } else if street, ok := addrMap["street_address"].(string); ok && street != "" { parts = append(parts, street) } else if line1, ok := addrMap["line1"].(string); ok && line1 != "" { parts = append(parts, line1) } if city, ok := addrMap["city"].(string); ok && city != "" { parts = append(parts, city) } if state, ok := addrMap["state"].(string); ok && state != "" { parts = append(parts, state) } if zip, ok := addrMap["zip"].(string); ok && zip != "" { parts = append(parts, zip) } else if zip, ok := addrMap["zip_code"].(string); ok && zip != "" { parts = append(parts, zip) } else if postal, ok := addrMap["postal_code"].(string); ok && postal != "" { parts = append(parts, postal) } if len(parts) > 0 { return strings.Join(parts, ", ") } return "" } func formatReportProperty(sb *strings.Builder, prop interface{}, indent string) bool { propMap, ok := prop.(map[string]interface{}) if !ok { return false } address := extractPropertyAddress(propMap) if address == "" { return false } sb.WriteString(fmt.Sprintf("%s%s %s", indent, reportDimStyle.Render("•"), reportValueStyle.Render(address))) var meta []string if propType, ok := propMap["type"].(string); ok && propType != "" { meta = append(meta, propType) } if value, ok := propMap["value"].(float64); ok && value > 0 { meta = append(meta, fmt.Sprintf("$%.0f", value)) } else if value, ok := propMap["assessed_value"].(float64); ok && value > 0 { meta = append(meta, fmt.Sprintf("assessed: $%.0f", value)) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", strings.Join(meta, ", ")))) } sb.WriteString("\n") detailIndent := indent + " " if ownership, ok := propMap["ownership"].(map[string]interface{}); ok { if ownerName, ok := ownership["owner_name"].(string); ok && ownerName != "" { sb.WriteString(fmt.Sprintf("%s%s %s\n", detailIndent, reportDimStyle.Render("Owner:"), reportValueStyle.Render(ownerName))) } if ownerType, ok := ownership["owner_type"].(string); ok && ownerType != "" { sb.WriteString(fmt.Sprintf("%s%s %s\n", detailIndent, reportDimStyle.Render("Type:"), reportValueStyle.Render(ownerType))) } } if mortgage, ok := propMap["mortgage"].(map[string]interface{}); ok { formatPropertyMortgage(sb, mortgage, detailIndent) } if mortgages, ok := propMap["mortgages"].([]interface{}); ok && len(mortgages) > 0 { if mortgageMap, ok := mortgages[0].(map[string]interface{}); ok { formatPropertyMortgage(sb, mortgageMap, detailIndent) } } if tax, ok := propMap["tax_assessment"].(map[string]interface{}); ok { formatPropertyTax(sb, tax, detailIndent) } if tax, ok := propMap["taxAssessment"].(map[string]interface{}); ok { formatPropertyTax(sb, tax, detailIndent) } return true } func formatPropertyMortgage(sb *strings.Builder, mortgage map[string]interface{}, indent string) { var mortgageInfo []string if lender, ok := mortgage["lender"].(string); ok && lender != "" { mortgageInfo = append(mortgageInfo, lender) } if amount, ok := mortgage["amount"].(float64); ok && amount > 0 { mortgageInfo = append(mortgageInfo, fmt.Sprintf("$%.0f", amount)) } else if amount, ok := mortgage["loan_amount"].(float64); ok && amount > 0 { mortgageInfo = append(mortgageInfo, fmt.Sprintf("$%.0f", amount)) } if date, ok := mortgage["date"].(string); ok && date != "" { mortgageInfo = append(mortgageInfo, date) } else if date, ok := mortgage["recording_date"].(string); ok && date != "" { mortgageInfo = append(mortgageInfo, date) } if len(mortgageInfo) > 0 { sb.WriteString(fmt.Sprintf("%s%s %s\n", indent, reportDimStyle.Render("Mortgage:"), reportValueStyle.Render(strings.Join(mortgageInfo, " | ")))) } } func formatPropertyTax(sb *strings.Builder, tax map[string]interface{}, indent string) { var taxInfo []string if assessed, ok := tax["assessed_value"].(float64); ok && assessed > 0 { taxInfo = append(taxInfo, fmt.Sprintf("assessed: $%.0f", assessed)) } if market, ok := tax["market_value"].(float64); ok && market > 0 { taxInfo = append(taxInfo, fmt.Sprintf("market: $%.0f", market)) } if taxAmount, ok := tax["tax_amount"].(float64); ok && taxAmount > 0 { taxInfo = append(taxInfo, fmt.Sprintf("tax: $%.0f", taxAmount)) } if year, ok := tax["year"].(float64); ok && year > 0 { taxInfo = append(taxInfo, fmt.Sprintf("year: %d", int(year))) } else if year, ok := tax["tax_year"].(string); ok && year != "" { taxInfo = append(taxInfo, fmt.Sprintf("year: %s", year)) } if len(taxInfo) > 0 { sb.WriteString(fmt.Sprintf("%s%s %s\n", indent, reportDimStyle.Render("Tax:"), reportValueStyle.Render(strings.Join(taxInfo, " | ")))) } } func formatReportVehicles(sb *strings.Builder, data map[string]interface{}) { vehicles, ok := data["vehicles"].([]interface{}) if !ok || len(vehicles) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ VEHICLES")) sb.WriteString("\n") for _, v := range vehicles { vehMap, ok := v.(map[string]interface{}) if !ok { continue } var parts []string if year, ok := vehMap["year"].(string); ok && year != "" { parts = append(parts, year) } else if year, ok := vehMap["year"].(float64); ok && year > 0 { parts = append(parts, fmt.Sprintf("%d", int(year))) } if make, ok := vehMap["make"].(string); ok && make != "" { parts = append(parts, make) } if model, ok := vehMap["model"].(string); ok && model != "" { parts = append(parts, model) } if len(parts) > 0 { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportValueStyle.Render(strings.Join(parts, " ")))) if vin, ok := vehMap["vin"].(string); ok && vin != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [VIN: %s]", vin))) } sb.WriteString("\n") } } sb.WriteString("\n") } func formatReportCriminalRecords(sb *strings.Builder, data map[string]interface{}) { records, ok := data["criminal_records"].([]interface{}) if !ok || len(records) == 0 { if crimRecords, ok := data["criminalRecords"].([]interface{}); ok && len(crimRecords) > 0 { records = crimRecords } else { return } } sb.WriteString(reportSectionStyle.Render("▸ CRIMINAL RECORDS")) sb.WriteString("\n") for _, r := range records { recMap, ok := r.(map[string]interface{}) if !ok { continue } formatCriminalRecord(sb, recMap) if enhanced, ok := recMap["enhanced_record"].(map[string]interface{}); ok { formatEnhancedCriminalRecord(sb, enhanced) } } sb.WriteString("\n") } func formatCriminalRecord(sb *strings.Builder, recMap map[string]interface{}) { offense := "" if o, ok := recMap["offense"].(string); ok && o != "" { offense = o } else if o, ok := recMap["charge"].(string); ok && o != "" { offense = o } if offense == "" { return } sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportWarningStyle.Render(offense))) var meta []string if caseType, ok := recMap["case_type"].(string); ok && caseType != "" { meta = append(meta, caseType) } if date, ok := recMap["date"].(string); ok && date != "" { meta = append(meta, date) } else if date, ok := recMap["offense_date"].(string); ok && date != "" { meta = append(meta, date) } if county, ok := recMap["county"].(string); ok && county != "" { meta = append(meta, county) } if state, ok := recMap["state"].(string); ok && state != "" { meta = append(meta, state) } if disposition, ok := recMap["disposition"].(string); ok && disposition != "" { meta = append(meta, disposition) } if len(meta) > 0 { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", strings.Join(meta, ", ")))) } sb.WriteString("\n") if crimeDetails, ok := recMap["crime_details"].(map[string]interface{}); ok { if severity, ok := crimeDetails["severity"].(string); ok && severity != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Severity:"), reportWarningStyle.Render(severity))) } if category, ok := crimeDetails["category"].(string); ok && category != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Category:"), reportValueStyle.Render(category))) } } if matchIndicators, ok := recMap["match_indicators"].(map[string]interface{}); ok { var indicators []string if name, ok := matchIndicators["name_match"].(bool); ok && name { indicators = append(indicators, "name") } if dob, ok := matchIndicators["dob_match"].(bool); ok && dob { indicators = append(indicators, "DOB") } if addr, ok := matchIndicators["address_match"].(bool); ok && addr { indicators = append(indicators, "address") } if len(indicators) > 0 { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Matched on:"), reportValueStyle.Render(strings.Join(indicators, ", ")))) } } } func formatEnhancedCriminalRecord(sb *strings.Builder, enhanced map[string]interface{}) { if caseNumber, ok := enhanced["case_number"].(string); ok && caseNumber != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Case #:"), reportValueStyle.Render(caseNumber))) } if court, ok := enhanced["court"].(string); ok && court != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Court:"), reportValueStyle.Render(court))) } if sentence, ok := enhanced["sentence"].(string); ok && sentence != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Sentence:"), reportValueStyle.Render(sentence))) } if filingDate, ok := enhanced["filing_date"].(string); ok && filingDate != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("Filed:"), reportValueStyle.Render(filingDate))) } } func formatReportVoterRecords(sb *strings.Builder, data map[string]interface{}) { voter, ok := data["voter_record"].(map[string]interface{}) if !ok { if records, ok := data["voter_records"].([]interface{}); ok && len(records) > 0 { if v, ok := records[0].(map[string]interface{}); ok { voter = v } } } if voter == nil { return } sb.WriteString(reportSectionStyle.Render("▸ VOTER REGISTRATION")) sb.WriteString("\n") if party, ok := voter["party"].(string); ok && party != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Party:"), reportValueStyle.Render(party))) } if status, ok := voter["status"].(string); ok && status != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Status:"), reportValueStyle.Render(status))) } if regDate, ok := voter["registration_date"].(string); ok && regDate != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("Registered:"), reportValueStyle.Render(regDate))) } if county, ok := voter["county"].(string); ok && county != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportLabelStyle.Render("County:"), reportValueStyle.Render(county))) } sb.WriteString("\n") } func formatReportSocialProfiles(sb *strings.Builder, data map[string]interface{}) { profiles, ok := data["social_profiles"].([]interface{}) if !ok || len(profiles) == 0 { profiles, ok = data["urls"].([]interface{}) if !ok || len(profiles) == 0 { return } } sb.WriteString(reportSectionStyle.Render("▸ SOCIAL PROFILES")) sb.WriteString("\n") for _, p := range profiles { switch profile := p.(type) { case string: if profile != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportHighlightStyle.Render(profile))) } case map[string]interface{}: url := "" if u, ok := profile["url"].(string); ok && u != "" { url = u } else if u, ok := profile["display"].(string); ok && u != "" { url = u } if url != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportHighlightStyle.Render(url))) if network, ok := profile["network"].(string); ok && network != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", network))) } else if domain, ok := profile["domain"].(string); ok && domain != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", domain))) } sb.WriteString("\n") } } } sb.WriteString("\n") } func formatReportImages(sb *strings.Builder, data map[string]interface{}) { images, ok := data["images"].([]interface{}) if !ok || len(images) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ IMAGES")) sb.WriteString("\n") for _, img := range images { switch image := img.(type) { case string: if image != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportDimStyle.Render(image))) } case map[string]interface{}: if url, ok := image["url"].(string); ok && url != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportDimStyle.Render(url))) } } } sb.WriteString("\n") } func formatReportTags(sb *strings.Builder, data map[string]interface{}) { tags, ok := data["tags"].([]interface{}) if !ok || len(tags) == 0 { return } sb.WriteString(reportSectionStyle.Render("▸ TAGS / DATA BREACH INFO")) sb.WriteString("\n") for _, t := range tags { switch tag := t.(type) { case string: if tag != "" { sb.WriteString(fmt.Sprintf(" %s %s\n", reportDimStyle.Render("•"), reportWarningStyle.Render(tag))) } case map[string]interface{}: content := "" if c, ok := tag["content"].(string); ok && c != "" { content = c } else if c, ok := tag["name"].(string); ok && c != "" { content = c } if content != "" { sb.WriteString(fmt.Sprintf(" %s %s", reportDimStyle.Render("•"), reportWarningStyle.Render(content))) if source, ok := tag["source"].(string); ok && source != "" { sb.WriteString(reportDimStyle.Render(fmt.Sprintf(" [%s]", source))) } sb.WriteString("\n") } } } sb.WriteString("\n") }