package cointop

import (
	"regexp"
	"strings"

	"github.com/miguelmota/cointop/cointop/common/levenshtein"
)

// SearchFieldView is structure for search field view
type SearchFieldView struct {
	*View
}

// NewSearchFieldView returns a new search field view
func NewSearchFieldView() *SearchFieldView {
	return &SearchFieldView{NewView("searchfield")}
}

// InputView is structure for help view
type InputView struct {
	*View
}

// NewInputView returns a new help view
func NewInputView() *InputView {
	return &InputView{NewView("input")}
}

func (ct *Cointop) openSearch() error {
	ct.debuglog("openSearch()")
	ct.State.searchFieldVisible = true
	ct.SetActiveView(ct.Views.SearchField.Name())
	return nil
}

func (ct *Cointop) cancelSearch() error {
	ct.debuglog("cancelSearch()")
	ct.State.searchFieldVisible = false
	ct.SetActiveView(ct.Views.Table.Name())
	return nil
}

func (ct *Cointop) doSearch() error {
	ct.debuglog("doSearch()")
	ct.Views.SearchField.Backing().Rewind()
	b := make([]byte, 100)
	n, err := ct.Views.SearchField.Backing().Read(b)

	// TODO: do this a better way (SoC)
	ct.State.filterByFavorites = false
	ct.State.portfolioVisible = false

	defer ct.SetActiveView(ct.Views.Table.Name())
	if err != nil {
		return nil
	}
	if n == 0 {
		return nil
	}
	q := string(b)
	// remove slash
	regex := regexp.MustCompile(`/(.*)`)
	matches := regex.FindStringSubmatch(q)
	if len(matches) > 0 {
		q = matches[1]
	}
	return ct.search(q)
}

func (ct *Cointop) search(q string) error {
	ct.debuglog("search()")
	q = strings.TrimSpace(strings.ToLower(q))
	idx := -1
	min := -1
	var hasprefixidx []int
	var hasprefixdist []int
	for i := range ct.State.allCoins {
		coin := ct.State.allCoins[i]
		name := strings.ToLower(coin.Name)
		symbol := strings.ToLower(coin.Symbol)
		// if query matches symbol, return immediately
		if symbol == q {
			ct.goToGlobalIndex(i)
			return nil
		}
		// if query matches name, return immediately
		if name == q {
			ct.goToGlobalIndex(i)
			return nil
		}
		// store index with the smallest levenshtein
		dist := levenshtein.DamerauLevenshteinDistance(name, q)
		if min == -1 || dist <= min {
			idx = i
			min = dist
		}
		// store index where query is substring to name
		if strings.HasPrefix(name, q) {
			if len(hasprefixdist) == 0 || dist < hasprefixdist[0] {
				hasprefixidx = append(hasprefixidx, i)
				hasprefixdist = append(hasprefixdist, dist)
			}
		}
	}
	// go to row if prefix match
	if len(hasprefixidx) > 0 && hasprefixidx[0] != -1 && min > 0 {
		ct.goToGlobalIndex(hasprefixidx[0])
		return nil
	}
	// go to row if levenshtein distance is small enough
	if idx > -1 && min <= 6 {
		ct.goToGlobalIndex(idx)
		return nil
	}
	return nil
}
