package solver

import (
	"log"
	"strconv"
	"time"
)

// Keep track and output progress.
// Calculate rates, display percentages, estimate the ETA till completion.
func (solver *Solver) Tracker() {

	// Add time tracking
	defer solver.timeTrack(time.Now(), "Validated solutions")
	log.Println("Validating solutions")

	// Determine if the main-loop is done
	var done bool

	// Tracking progress in percentages
	var percentage float32
	// Tracking progress in validated solutions
	var track int

	// Tracking the rate, starting point
	var rateStart uint64
	// Tracking the rate, difference between previous iterations
	var rateDiff uint64

	// Tracking duration
	var timerStart = time.Now()

	// Estimation how long it will take
	var est_fin string

	// While not needed for rateDiff anymore, it makes estimation calculations more accurate. ☹️
	time.Sleep(time.Second)

	// for solver.Iter != solver.counter { // Start for-loop
	for !done {

		// Determine how far we are.
		percentage = (float32(solver.counter.Load()) / (float32(solver.Iter) / 100))

		// Reset the loop
		rateDiff = solver.counter.Load() - rateStart

		if track <= int(percentage) || rateDiff == 0 { // Start if-statement

			// Make sure something happened, making rateStart the only reliable variable
			if solver.Iter == solver.counter.Load() {
				percentage = 100
				solver.counter.Store(solver.Iter)
				done = true
			}

			timer_elapsed := time.Since(timerStart)
			solver.rates = append(solver.rates, rateDiff)
			rate_avg := solver.calcAVG()

			// Estimate when this is finished
			if rateDiff == 0 {
				est_fin = "N/A"
			} else {
				duration_int := (solver.Iter - solver.counter.Load()) / rate_avg
				duration_string := strconv.Itoa(int(duration_int)) + "s"
				est, err := time.ParseDuration(duration_string)
				if err != nil {
					est_fin = "parse error"
				} else {
					est_fin = est.String()
				}
			}

			// Printing the progress
			log.Println("Processing: " + strconv.Itoa(int(percentage)) + "% (" + strconv.FormatUint(solver.counter.Load(), 10) + "/" + strconv.Itoa(int(solver.Iter)) + "); Rate: " + strconv.FormatUint(rateDiff, 10) + "/sec for " + timer_elapsed.String() + "; Time left (est.): " + est_fin)

			// After we are done printing, exit this for-loop
			if percentage == 100 {
				break
			}

			// Wrap up the loop or break
			if int(percentage) > track {
				track = int(percentage)
			} else {
				track = track + 1
			}

			timerStart = time.Now()

		}

		// Resert the rate counter
		rateStart = solver.counter.Load()

		// Sleep for a second
		if solver.Iter != solver.counter.Load() {
			time.Sleep(1 * time.Second)
		}
	} // End for-loop

}
