package discovery

import (
	"context"
	"strings"
	"unicode"
)

func (s *Service) loadNCContacts(ctx context.Context, ncUserID, bookID string) []ncContact {
	if s.nc == nil || ncUserID == "" {
		return nil
	}
	if bookID == "" {
		bookID = "contacts"
	}
	path := "/addressbooks/" + ncUserID + "/" + bookID + "/"
	contacts, err := s.nc.ListContacts(ctx, ncUserID, path)
	if err != nil {
		s.logger.Warn("load nc contacts for enrichment", "error", err)
		return nil
	}
	return contacts
}

func (s *Service) resolveDiscoveryNCContext(ctx context.Context, externalUserID string) (ncUserID, bookID string) {
	bookID = "contacts"
	_ = s.db.QueryRow(ctx, `
		SELECT COALESCE(NULLIF(nc_user_id, ''), ''), COALESCE(NULLIF(book_id, ''), 'contacts')
		FROM contact_discovery_scans
		WHERE user_id = (SELECT id FROM users WHERE external_id = $1)
		ORDER BY started_at DESC
		LIMIT 1
	`, externalUserID).Scan(&ncUserID, &bookID)
	return
}

func findExistingContact(contacts []ncContact, email string) *ncContact {
	email = strings.ToLower(strings.TrimSpace(email))
	for i := range contacts {
		if strings.EqualFold(strings.TrimSpace(contacts[i].Email), email) {
			return &contacts[i]
		}
	}
	return nil
}

func normalizePhone(s string) string {
	var b strings.Builder
	for _, r := range s {
		if unicode.IsDigit(r) {
			b.WriteRune(r)
		}
	}
	return b.String()
}

func phonesEqual(a, b string) bool {
	na, nb := normalizePhone(a), normalizePhone(b)
	if na == "" || nb == "" {
		return false
	}
	if len(na) >= 9 && len(nb) >= 9 {
		return na[len(na)-9:] == nb[len(nb)-9:]
	}
	return na == nb
}

func stringsEqualFoldTrim(a, b string) bool {
	return strings.EqualFold(strings.TrimSpace(a), strings.TrimSpace(b))
}

func suggestionAlreadyOnContact(existing *ncContact, sug Suggestion) bool {
	if existing == nil {
		return false
	}
	val := strings.TrimSpace(sug.SuggestedValue)
	if val == "" {
		return true
	}
	switch sug.FieldPath {
	case "full_name":
		return stringsEqualFoldTrim(val, existing.FullName)
	case "company":
		return stringsEqualFoldTrim(val, existing.Org)
	case "phones":
		return phonesEqual(val, existing.Phone)
	case "emails":
		return strings.EqualFold(val, strings.TrimSpace(existing.Email))
	default:
		return false
	}
}

func filterRedundantSuggestions(suggestions []Suggestion, contacts []ncContact) []Suggestion {
	if len(suggestions) == 0 || len(contacts) == 0 {
		return suggestions
	}
	byUID := make(map[string]*ncContact, len(contacts))
	for i := range contacts {
		byUID[contacts[i].UID] = &contacts[i]
	}
	filtered := suggestions[:0]
	for _, sug := range suggestions {
		if sug.SuggestionType != "enrich_contact" || sug.TargetContactUID == "" {
			filtered = append(filtered, sug)
			continue
		}
		if suggestionAlreadyOnContact(byUID[sug.TargetContactUID], sug) {
			continue
		}
		filtered = append(filtered, sug)
	}
	return filtered
}

func enrichExistingContactSuggestions(profileID, contactUID string, data *EnrichedContactData, existing *ncContact) []Suggestion {
	if data == nil || existing == nil {
		return nil
	}
	var out []Suggestion

	addIfMissing := func(fieldPath, value, label string) {
		value = strings.TrimSpace(value)
		if value == "" {
			return
		}
		sug := Suggestion{
			ProfileID:        profileID,
			TargetContactUID: contactUID,
			SuggestionType:   "enrich_contact",
			FieldPath:        fieldPath,
			SuggestedValue:   value,
			SuggestedLabel:   label,
			Confidence:       0.7,
			Status:           SuggestionPending,
		}
		if suggestionAlreadyOnContact(existing, sug) {
			return
		}
		out = append(out, sug)
	}

	fullName := strings.TrimSpace(data.FirstName + " " + data.LastName)
	addIfMissing("full_name", fullName, "")
	addIfMissing("company", data.Company, "")
	addIfMissing("job_title", data.JobTitle, "")
	for _, p := range data.Phones {
		addIfMissing("phones", p.Value, p.Label)
	}
	for _, e := range data.Emails {
		if !strings.EqualFold(e.Value, existing.Email) {
			addIfMissing("emails", e.Value, e.Label)
		}
	}
	for _, sp := range data.SocialProfiles {
		addIfMissing("social_profiles", sp.Value, sp.Label)
	}

	return out
}
