// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package perfdata contains a client for the performance data storage server.
package perfdata

import (
	"context"
	"encoding/json"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"net/url"

	"golang.org/x/net/context/ctxhttp"
	"golang.org/x/perf/storage/benchfmt"
)

// A Client issues queries to a performance data storage server.
// It is safe to use from multiple goroutines simultaneously.
type Client struct {
	// BaseURL is the base URL of the storage server.
	BaseURL string
	// HTTPClient is the HTTP client for sending requests. If nil, http.DefaultClient will be used.
	HTTPClient *http.Client
}

// httpClient returns the http.Client to use for requests.
func (c *Client) httpClient() *http.Client {
	if c.HTTPClient != nil {
		return c.HTTPClient
	}
	return http.DefaultClient
}

// Query searches for results matching the given query string. The
// result is a stream of bytes containing text benchmark data. This data
// may be parsed and processed by the x/perf/benchfmt package.
//
// The query string is first parsed into quoted words (as in the shell)
// and then each word must be formatted as one of the following:
// key:value - exact match on label "key" = "value"
// key>value - value greater than (useful for dates)
// key<value - value less than (also useful for dates)
func (c *Client) Query(ctx context.Context, q string) (io.ReadCloser, error) {
	hc := c.httpClient()

	resp, err := ctxhttp.Get(ctx, hc, c.BaseURL+"/search?"+url.Values{"q": []string{q}}.Encode())
	if err != nil {
		return nil, err
	}
	if resp.StatusCode != 200 {
		defer resp.Body.Close()
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return nil, err
		}
		return nil, fmt.Errorf("%s", body)
	}
	return resp.Body, nil
}

// UploadInfo represents an upload summary.
type UploadInfo struct {
	Count       int
	UploadID    string
	LabelValues benchfmt.Labels `json:",omitempty"`
}

// ListUploads searches for uploads containing results matching the given query string.
// The query may be empty, in which case all uploads will be returned.
// extraLabels specifies other labels to be retrieved.
// If limit is 0, no limit will be provided to the server.
// The uploads are returned starting with the most recent upload.
func (c *Client) ListUploads(ctx context.Context, q string, extraLabels []string, limit int) *UploadList {
	hc := c.httpClient()

	v := url.Values{"extra_label": extraLabels}
	if q != "" {
		v["q"] = []string{q}
	}
	if limit != 0 {
		v["limit"] = []string{fmt.Sprintf("%d", limit)}
	}

	u := c.BaseURL + "/uploads"
	if len(v) > 0 {
		u += "?" + v.Encode()
	}
	resp, err := ctxhttp.Get(ctx, hc, u)
	if err != nil {
		return &UploadList{err: err}
	}
	if resp.StatusCode != 200 {
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return &UploadList{err: err}
		}
		return &UploadList{err: fmt.Errorf("%s", body)}
	}
	return &UploadList{body: resp.Body, dec: json.NewDecoder(resp.Body)}
}

// UploadList is the result of ListUploads.
// Use Next to advance through the rows, making sure to call Close when done:
//
//	q := db.ListUploads("key:value")
//	defer q.Close()
//	for q.Next() {
//	  id, count := q.Row()
//	  labels := q.LabelValues()
//	  ...
//	}
//	err = q.Err() // get any error encountered during iteration
//	...
type UploadList struct {
	body io.Closer
	dec  *json.Decoder
	// from last call to Next
	ui  UploadInfo
	err error
}

// Next prepares the next result for reading with the Result
// method. It returns false when there are no more results, either by
// reaching the end of the input or an error.
func (ul *UploadList) Next() bool {
	if ul.err != nil {
		return false
	}

	// Clear UploadInfo before decoding new value.
	ul.ui = UploadInfo{}

	ul.err = ul.dec.Decode(&ul.ui)
	return ul.err == nil
}

// Info returns the most recent UploadInfo generated by a call to Next.
func (ul *UploadList) Info() UploadInfo {
	return ul.ui
}

// Err returns the error state of the query.
func (ul *UploadList) Err() error {
	if ul.err == io.EOF {
		return nil
	}
	return ul.err
}

// Close frees resources associated with the query.
func (ul *UploadList) Close() error {
	if ul.body != nil {
		err := ul.body.Close()
		ul.body = nil
		return err
	}
	return ul.Err()
}

// NewUpload starts a new upload to the storage server.
// The upload must have Abort or Commit called on it.
// If the server requires authentication for uploads, c.HTTPClient should be set to the result of oauth2.NewClient.
func (c *Client) NewUpload(ctx context.Context) *Upload {
	hc := c.httpClient()

	pr, pw := io.Pipe()
	mpw := multipart.NewWriter(pw)

	req, err := http.NewRequest("POST", c.BaseURL+"/upload", pr)
	if err != nil {
		return &Upload{err: err}
	}
	req.Header.Set("Content-Type", mpw.FormDataContentType())
	req.Header.Set("User-Agent", "golang.org/x/build/perfdata")
	errCh := make(chan error)
	u := &Upload{pw: pw, mpw: mpw, errCh: errCh}
	go func() {
		resp, err := ctxhttp.Do(ctx, hc, req)
		if err != nil {
			errCh <- err
			return
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			body, _ := io.ReadAll(resp.Body)
			errCh <- fmt.Errorf("upload failed: %v\n%s", resp.Status, body)
			return
		}
		status := &UploadStatus{}
		if err := json.NewDecoder(resp.Body).Decode(status); err != nil {
			errCh <- err
		}
		u.status = status
		errCh <- nil
	}()
	return u
}

// UploadStatus contains information about a successful upload.
type UploadStatus struct {
	// UploadID is the upload ID assigned to the upload.
	UploadID string `json:"uploadid"`
	// FileIDs is the list of file IDs assigned to the files in the upload.
	FileIDs []string `json:"fileids"`
	// ViewURL is a server-supplied URL to view the results.
	ViewURL string `json:"viewurl"`
}

// An Upload is an in-progress upload.
// Use CreateFile to upload one or more files, then call Commit or Abort.
//
//	u := client.NewUpload()
//	w, err := u.CreateFile()
//	if err != nil {
//	  u.Abort()
//	  return err
//	}
//	fmt.Fprintf(w, "BenchmarkResult 1 1 ns/op\n")
//	if err := u.Commit(); err != nil {
//	  return err
//	}
type Upload struct {
	pw     io.WriteCloser
	mpw    *multipart.Writer
	status *UploadStatus
	// errCh is used to report the success/failure of the HTTP request
	errCh chan error
	// err is the first observed error; it is only accessed from user-called methods for thread safety
	err error
}

// CreateFile creates a new upload with the given name.
// The Writer may be used until CreateFile is called again.
// name may be the empty string if the file does not have a name.
func (u *Upload) CreateFile(name string) (io.Writer, error) {
	if u.err != nil {
		return nil, u.err
	}
	return u.mpw.CreateFormFile("file", name)
}

// Commit attempts to commit the upload.
func (u *Upload) Commit() (*UploadStatus, error) {
	if u.err != nil {
		return nil, u.err
	}
	if u.err = u.mpw.WriteField("commit", "1"); u.err != nil {
		u.Abort()
		return nil, u.err
	}
	if u.err = u.mpw.Close(); u.err != nil {
		u.Abort()
		return nil, u.err
	}
	u.mpw = nil
	if u.err = u.pw.Close(); u.err != nil {
		u.Abort()
		return nil, u.err
	}
	u.pw = nil
	u.err = <-u.errCh
	u.errCh = nil
	if u.err != nil {
		return nil, u.err
	}
	return u.status, nil
}

// Abort attempts to cancel the in-progress upload.
func (u *Upload) Abort() error {
	if u.mpw != nil {
		u.mpw.WriteField("abort", "1")
		// Writing the 'abort' field will cause the server to send back an error response.
		u.mpw.Close()
		u.mpw = nil
	}
	if u.pw != nil {
		u.pw.Close()
		u.pw = nil
	}
	err := <-u.errCh
	u.errCh = nil
	if u.err == nil {
		u.err = err
	}
	return u.err
}
