package message

import (
	"fmt"
	"strings"
	"unicode"
)

const maxScopeSearchRankTerms = 8

func buildScopeSearchRankSQL(query string, firstPlaceholder int) (string, []any, string) {
	exactQuery := strings.Join(strings.Fields(strings.TrimSpace(query)), " ")
	args := []any{exactQuery}
	exactPlaceholder := fmt.Sprintf("$%d", firstPlaceholder)
	nextPlaceholder := firstPlaceholder + 1

	termConditions := make([]string, 0, maxScopeSearchRankTerms)
	for _, term := range scopeSearchRankingTerms(query) {
		termConditions = append(termConditions, fmt.Sprintf("LOCATE($%d, LOWER(docs.content)) > 0", nextPlaceholder))
		args = append(args, term)
		nextPlaceholder++
	}
	allTermsCondition := "FALSE"
	if len(termConditions) > 0 {
		allTermsCondition = strings.Join(termConditions, " AND ")
	}

	rankSQL := fmt.Sprintf(`CASE
	    WHEN LOCATE(LOWER(%s), LOWER(docs.content)) > 0 THEN 0
	    WHEN %s THEN 1
	    ELSE 2
	  END`, exactPlaceholder, allTermsCondition)
	return rankSQL, args, fmt.Sprintf("$%d", nextPlaceholder)
}

func scopeSearchRankingTerms(query string) []string {
	seen := make(map[string]struct{}, maxScopeSearchRankTerms)
	terms := make([]string, 0, maxScopeSearchRankTerms)
	for _, field := range strings.FieldsFunc(strings.ToLower(strings.TrimSpace(query)), func(r rune) bool {
		return !unicode.IsLetter(r) && !unicode.IsDigit(r)
	}) {
		term := strings.TrimSpace(field)
		if term == "" {
			continue
		}
		if _, ok := seen[term]; ok {
			continue
		}
		seen[term] = struct{}{}
		terms = append(terms, term)
		if len(terms) >= maxScopeSearchRankTerms {
			break
		}
	}
	return terms
}
