// 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)
