// Package spinner contains functions for displaying progress updates
// with a spinning icon that shows the user that progress is being made.
package spinner

import (
	"fmt"
	"strings"
	"time"

	"github.com/aws-cloudformation/rain/internal/config"
	"github.com/aws-cloudformation/rain/internal/console"
)

var spin = []string{"˙", "·", ".", " "}

var hasTimer = false

var statuses []string
var count = 0
var startTime time.Time
var paused = false

var lastLine = ""

func init() {
	statuses = make([]string, 0)

	go func() {
		for console.IsTTY && !config.Debug {
			if !paused && len(statuses) > 0 {
				update()
				count = (count + 1) % len(spin)
			}

			time.Sleep(time.Second / 7)
		}
	}()
}

func update() {
	if config.Debug {
		if len(statuses) > 0 {
			config.Debugf("%s", statuses[len(statuses)-1])
			statuses = statuses[:len(statuses)-1]
		}

		return
	}

	if !console.IsTTY {
		return
	}

	console.ClearLines(console.CountLines(lastLine))

	if !paused && len(statuses) > 0 {
		status := strings.TrimSpace(statuses[len(statuses)-1])

		if hasTimer {
			lastLine = fmt.Sprintf("%s%s%s %s %s",
				console.Cyan(spin[count]),
				console.Cyan(spin[(count+3)%len(spin)]),
				console.Cyan(spin[(count+5)%len(spin)]),
				time.Since(startTime).Truncate(time.Second),
				status,
			)
		} else {
			lastLine = fmt.Sprintf("%s %s%s%s",
				status,
				console.Cyan(spin[count]),
				console.Cyan(spin[(count+3)%len(spin)]),
				console.Cyan(spin[(count+5)%len(spin)]),
			)
		}

		fmt.Print(lastLine)
	}
}

// Push enables the spinner and displays the provided message
func Push(status string) {
	statuses = append(statuses, status)

	update()
}

// StartTimer enables the spinner and displays a timer counting upwards from 0
func StartTimer(status string) {
	startTime = time.Now()
	hasTimer = true

	Push(status)
}

// StopTimer disables the timer
func StopTimer() {
	hasTimer = false

	Pop()

	// TODO: Return the elapsed time:
	// time.Since(startTime).Truncate(time.Second),
}

// Pop removes the move recent status and stops the spinner if there are no more messages
func Pop() {
	if len(statuses) > 0 {
		statuses = statuses[:len(statuses)-1]
	}

	if console.IsTTY {
		update()
	}
}

// Pause pauses the spinner so that you can interact with the console
func Pause() {
	paused = true

	if console.IsTTY {
		update()
	}
}

// Resume resumes the spinner
func Resume() {
	paused = false

	if console.IsTTY {
		update()
	}
}

// Stop empties all spinner messages and stops the spinner
func Stop() {
	statuses = make([]string, 0)

	if console.IsTTY {
		update()
	}
}

// Update causes the spinner to update - use this if you have changed the display and need the spinner to redraw
func Update() {
	update()
}
