package strat

import (
	"sort"
	"strconv"

	"github.com/curusarn/resh/pkg/records"
	"github.com/mb-14/gomarkov"
)

// MarkovChain prediction/recommendation strategy
type MarkovChain struct {
	Order   int
	history []string
}

type strMarkEntry struct {
	cmdLine   string
	transProb float64
}

// Init see name
func (s *MarkovChain) Init() {
	s.history = nil
}

// GetTitleAndDescription see name
func (s *MarkovChain) GetTitleAndDescription() (string, string) {
	return "markov chain (order " + strconv.Itoa(s.Order) + ")", "Use markov chain to recommend commands"
}

// GetCandidates see name
func (s *MarkovChain) GetCandidates() []string {
	if len(s.history) < s.Order {
		return s.history
	}
	chain := gomarkov.NewChain(s.Order)

	chain.Add(s.history)

	cmdLinesSet := map[string]bool{}
	var entries []strMarkEntry
	for _, cmdLine := range s.history {
		if cmdLinesSet[cmdLine] {
			continue
		}
		cmdLinesSet[cmdLine] = true
		prob, _ := chain.TransitionProbability(cmdLine, s.history[len(s.history)-s.Order:])
		entries = append(entries, strMarkEntry{cmdLine: cmdLine, transProb: prob})
	}
	sort.Slice(entries, func(i int, j int) bool { return entries[i].transProb > entries[j].transProb })
	var hist []string
	for _, item := range entries {
		hist = append(hist, item.cmdLine)
	}
	// log.Println("################")
	// log.Println(s.history[len(s.history)-s.order:])
	// log.Println(" -> ")
	// x := math.Min(float64(len(hist)), 5)
	// log.Println(hist[:int(x)])
	// log.Println("################")
	return hist
}

// AddHistoryRecord see name
func (s *MarkovChain) AddHistoryRecord(record *records.EnrichedRecord) error {
	s.history = append(s.history, record.CmdLine)
	// s.historySet[record.CmdLine] = true
	return nil
}

// ResetHistory see name
func (s *MarkovChain) ResetHistory() error {
	s.Init()
	return nil
}
