package searcher

// |@@| C

import (
	"context"
	"strings"
)

type Searcher struct {
	Data struct {
		values   []SearchValue
		ready    bool
		indexing bool
	}
}

type ScopeItem struct {
	Name  string
	Value string
	Text  string
}

type SearchValue struct {
	Id      string
	Text    string
	ModelId string
	Model   string
	Url     string
	Index   int
	Scope   []*ScopeItem
}

func (this *Searcher) IsReady() bool {
	return this.Data.ready
}

func (this *Searcher) IsIndexing() bool {
	return this.Data.indexing
}

type IndexingFunction func(ctx context.Context) []SearchValue

func (this *Searcher) Indexing(ctx context.Context, function IndexingFunction) {
	if this.Data.indexing == true {
		return
	}
	this.Data.indexing = true
	this.Data.values = function(ctx)
	this.Data.indexing = false
}

type Mod struct {
	Kind          string
	Text          string
	ModelLimit    string
	HasModelLimit bool
	HasScope      bool
	Scope         *ScopeItem
}

func (this *Searcher) SearchValues(ctx context.Context, kind string, search string, scope []*ScopeItem) []SearchValue {
	var values []SearchValue
	mod := this.searchMod(search)
	mod.Kind = kind
	if len(scope) > 0 {
		mod.HasScope = true
		mod.Scope = scope[0]
	}

	for _, value := range this.Data.values {
		if mod.HasModelLimit == true {
			if value.Model != mod.ModelLimit {
				continue
			}
		}

		if !strings.Contains(value.Text, mod.Text) {
			continue
		}
		if mod.Kind == "scoped" && mod.HasScope == true && !this.valueIncludedInScope(value.Scope, mod.Scope) {
			continue
		}
		values = append(values, value)
		if len(values) >= 10 {
			return values
		}
	}
	return values
}

func (this *Searcher) searchMod(search string) Mod {
	search = strings.ToLower(search)
	ss := strings.Split(search, " ")
	var ss2 []string
	var mod Mod
	for _, s := range ss {
		if strings.Contains(s, ":") {
			if strings.HasPrefix(s, ":") {
				s = strings.TrimPrefix(s, ":")
				s = strings.ReplaceAll(strings.ToLower(s), " ", "_")
				mod.HasModelLimit = true
				mod.ModelLimit = s
			}
			continue
		}
		ss2 = append(ss2, s)
	}
	mod.Text = strings.Join(ss2, " ")
	return mod
}

func (this *Searcher) valueIncludedInScope(scopeItems []*ScopeItem, scopeLooked *ScopeItem) bool {
	for _, item := range scopeItems {
		if item.Name == scopeLooked.Name && item.Value == scopeLooked.Value {
			return true
		}
	}
	return false
}
