package pkgserver

import (
	"cmp"
	"maps"
	"regexp"
	"slices"
	"time"
)

type searchCache map[string]searchCacheEntry
type searchResult struct {
	NameIndices [][]int `json:"name_matches"`
	DescIndices [][]int `json:"desc_matches,omitempty"`
	Score       float64 `json:"score"`
	*metadata
}
type searchCacheEntry struct {
	query   string
	results []searchResult
	expiry  time.Time
}

func (index *packageIndex) performSearchQuery(limit int, i int, search string, desc bool) (int, []searchResult, error) {
	query := search
	if desc {
		query += ";withDesc"
	}
	entry, ok := index.search[query]
	if ok && len(entry.results) > 0 {
		return len(entry.results), entry.results[min(i, len(entry.results)-1):min(i+limit, len(entry.results))], nil
	}

	regex, err := regexp.Compile(search)
	if err != nil {
		return 0, make([]searchResult, 0), err
	}
	res := make([]searchResult, 0)
	for p := range maps.Values(index.names) {
		nameIndices := regex.FindAllIndex([]byte(p.Name), -1)
		var descIndices [][]int = nil
		if desc {
			descIndices = regex.FindAllIndex([]byte(p.Description), -1)
		}
		if nameIndices == nil && descIndices == nil {
			continue
		}
		score := float64(indexsum(nameIndices)) / (float64(len(nameIndices)) + 1)
		if desc {
			score += float64(indexsum(descIndices)) / (float64(len(descIndices)) + 1) / 10.0
		}
		res = append(res, searchResult{
			NameIndices: nameIndices,
			DescIndices: descIndices,
			Score:       score,
			metadata:    p,
		})
	}
	slices.SortFunc(res[:], func(a, b searchResult) int { return -cmp.Compare(a.Score, b.Score) })
	expiry := time.Now().Add(1 * time.Minute)
	entry = searchCacheEntry{
		query:   search,
		results: res,
		expiry:  expiry,
	}
	index.search[query] = entry

	return len(res), res[i:min(i+limit, len(entry.results))], nil
}
func (s *searchCache) clean() {
	maps.DeleteFunc(*s, func(_ string, v searchCacheEntry) bool {
		return v.expiry.Before(time.Now())
	})
}
func indexsum(in [][]int) int {
	sum := 0
	for i := range in {
		sum += in[i][1] - in[i][0]
	}
	return sum
}
