// Package progress is for tracking the progress of long running tasks on the
// backend in a way that can be reflected in the UI.
//
// We have multiple long running queries like /frame/start and /dryrun/start
// that start those long running processes and we need to give feedback to the
// user on how they are proceeding.
//
// The dryrun progress information contains different info with different stages
// and steps. For example, dryrun progress looks like this:
//
//   Step: 1/1
//   Query: "sub_result=max_rss_mb"
//   Stage: Looking for regressions in query results.
//   Commit: 51643
//   Details: "Filtered Traces: Num Before: 95 Num After: 92 Delta: 3"
//
// Which is just a series of key/value pairs of strings. So our common Progress
// interface allows for creating a set of key/value pairs to be displayed, along
// with the Status of the current process, and any results once the process has
// finished.
package progress

import (
	"encoding/json"
	"io"
	"sync"
)

// Status of a process.
type Status string

const (
	// Running mean a process is still running.
	Running Status = "Running"

	// Finished means the process has finished.
	Finished Status = "Finished"

	// Error means the process has finished with and error.
	Error Status = "Error"
)

// ErrorMessageKey is the key in Messages used to store the string passed to
// Error().
const ErrorMessageKey = "Error"

// AllStatus contains all values of type State.
var AllStatus = []Status{Running, Finished, Error}

// Message is a key value pair of strings, used in SerializedProgress.
type Message struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

// SerializedProgress is the shape of the JSON emitted from Progress.JSON().
type SerializedProgress struct {
	Status    Status      `json:"status"`
	Messsages []*Message  `json:"messages" go2ts:"ignorenil"`
	Results   interface{} `json:"results,omitempty"`

	// URL to use in the next polling step.
	URL string `json:"url"`
}

// Progress is the interface for reporting on the progress of a long running
// process.
//
// Once a Progress has left the Running status it can no longer be modified, and
// modifying methods like Error() and Results() will panic.
//
// A Progress should only be finalized, by calling Error(), Finished(), or
// FinishedWithResults() at the outermost calling level. For example, in an HTTP
// handler function you can kick off a long running process like this:
//
//    prog := new Progress()
//    go func() {
//        err, value := SomeLongRunningFuncThatOnlyReturnsWhenItsDone(ctx, prog)
//        if err != nil {
//            prog.Error("Some failure message")
//        } else {
//            prog.FinishedWithResults(value)
//        }
//    }()
//
type Progress interface {
	// Message adds or updates a message in a progress recorder. If the key
	// matches an existing message it will replace that key's value.
	Message(key, value string)

	// Results is called with the Results that are to be serialized via
	// SerializedProgress. Use this to store intermediate results or if results
	// are accumulated incrementally before the process is Finished.
	Results(interface{})

	// Error sets the Progress status to Error.
	//
	// The passed in string is stored at ErrorMessageKey in Messages.
	Error(string)

	// Finished sets the Progress status to Finished. Should only be used if
	// Results() has been called to fill in intermediate results, otherwise use
	// FinishedWithResults() to avoid race conditions.
	Finished()

	// FinishedWithResults sets the Progress status to Finished with the given
	// result.
	FinishedWithResults(interface{})

	// Status returns the current Status.
	Status() Status

	// URL sets the URL for the next progress update.
	URL(string)

	// JSON writes the data serialized as JSON. The shape is SerializedProgress.
	JSON(w io.Writer) error
}

// progress implements Progress.
type progress struct {
	mutex sync.Mutex
	state SerializedProgress
}

// New returns a new Progress in the Running state.
func New() *progress {
	return &progress{
		state: SerializedProgress{
			Status:    Running,
			Messsages: []*Message{},
		},
	}
}

// message implements Message. Callers are expected to already have the mutex.
func (p *progress) message(key, value string) {
	for _, m := range p.state.Messsages {
		if m.Key == key {
			m.Value = value
			return
		}
	}
	p.state.Messsages = append(p.state.Messsages, &Message{
		Key:   key,
		Value: value,
	})
}

// Message implements the Progress interface.
func (p *progress) Message(key, value string) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.message(key, value)
}

// Finished implements the Progress interface.
func (p *progress) Finished() {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.state.Status = Finished
}

// Results implements the Progress interface.
func (p *progress) Results(res interface{}) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.state.Results = res
}

// Results implements the Progress interface.
func (p *progress) FinishedWithResults(res interface{}) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.state.Status = Finished
	p.state.Results = res
}

// Error implements the Progress interface.
func (p *progress) Error(msg string) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.state.Status = Error
	p.message(ErrorMessageKey, msg)
}

// Status implements the Progress interface.
func (p *progress) Status() Status {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	return p.state.Status
}

// URL implements the Progress interface.
func (p *progress) URL(url string) {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	if p.state.Status != Running {
		panic("Progress is already Finished")
	}
	p.state.URL = url
}

// Message implements the Progress interface.
func (p *progress) JSON(w io.Writer) error {
	p.mutex.Lock()
	defer p.mutex.Unlock()
	return json.NewEncoder(w).Encode(p.state)
}

// Assert that progress implements the Progress interface.
var _ Progress = (*progress)(nil)
