// dryrun allows testing an Alert and seeing the regression it would find.
package dryrun

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"sort"

	"go.skia.org/infra/go/auditlog"
	"go.skia.org/infra/go/httputils"
	"go.skia.org/infra/go/sklog"
	"go.skia.org/infra/perf/go/dataframe"
	perfgit "go.skia.org/infra/perf/go/git"
	"go.skia.org/infra/perf/go/git/provider"
	"go.skia.org/infra/perf/go/progress"
	"go.skia.org/infra/perf/go/regression"
	"go.skia.org/infra/perf/go/shortcut"
	"go.skia.org/infra/perf/go/types"
)

// RegressionAtCommit is a Regression found for a specific commit.
type RegressionAtCommit struct {
	CID        provider.Commit        `json:"cid"`
	Regression *regression.Regression `json:"regression"`
}

// Requests handles HTTP request for doing dryruns.
type Requests struct {
	perfGit       *perfgit.Git
	shortcutStore shortcut.Store
	dfBuilder     dataframe.DataFrameBuilder
	tracker       progress.Tracker
	paramsProvier regression.ParamsetProvider
}

// New create a new dryrun Request processor.
func New(perfGit *perfgit.Git, tracker progress.Tracker, shortcutStore shortcut.Store, dfBuilder dataframe.DataFrameBuilder, paramsProvider regression.ParamsetProvider) *Requests {
	ret := &Requests{
		perfGit:       perfGit,
		shortcutStore: shortcutStore,
		dfBuilder:     dfBuilder,
		tracker:       tracker,
		paramsProvier: paramsProvider,
	}
	return ret
}

// StartHandler starts a dryrun.
func (d *Requests) StartHandler(w http.ResponseWriter, r *http.Request) {
	// Do not use r.Context() since this kicks off a background process.
	ctx := context.Background()
	w.Header().Set("Content-Type", "application/json")

	req := regression.NewRegressionDetectionRequest()
	if err := json.NewDecoder(r.Body).Decode(req); err != nil {
		httputils.ReportError(w, err, "Could not decode POST body.", http.StatusInternalServerError)
		return
	}
	auditlog.LogWithUser(r, "", "dryrun", req)
	d.tracker.Add(req.Progress)

	if req.Alert.Query == "" {
		req.Progress.Error("Query must not be empty.")
		if err := req.Progress.JSON(w); err != nil {
			sklog.Errorf("Failed to encode paramset: %s", err)
		}
		return
	}
	if err := req.Alert.Validate(); err != nil {
		req.Progress.Error(err.Error())
		if err := req.Progress.JSON(w); err != nil {
			sklog.Errorf("Failed to encode paramset: %s", err)
		}
		return
	}

	foundRegressions := map[types.CommitNumber]*regression.Regression{}

	// Create a callback that will be passed each found Regression. It will
	// update the Progress after each new regression is found.
	detectorResponseProcessor := func(queryRequest *regression.RegressionDetectionRequest, clusterResponse []*regression.RegressionDetectionResponse, message string) {
		// Loop over clusterResponse, convert each one to a regression, and merge with running.Regressions.
		for _, cr := range clusterResponse {
			c, reg, err := regression.RegressionFromClusterResponse(ctx, cr, req.Alert, d.perfGit)
			if err != nil {
				sklog.Errorf("Failed to convert to Regression: %s", err)
				return
			}
			req.Progress.Message("Step", fmt.Sprintf("%d/%d", queryRequest.Step+1, queryRequest.TotalQueries))
			req.Progress.Message("Query", fmt.Sprintf("%q", queryRequest.Query()))
			req.Progress.Message("Stage", "Looking for regressions in query results.")
			req.Progress.Message("Commit", fmt.Sprintf("%d", c.CommitNumber))
			req.Progress.Message("Details", message)
			// We might not have found any regressions.
			if reg.Low == nil && reg.High == nil {
				continue
			}
			if origReg, ok := foundRegressions[c.CommitNumber]; !ok {
				foundRegressions[c.CommitNumber] = reg
			} else {
				foundRegressions[c.CommitNumber] = origReg.Merge(reg)
			}

		}

		// Now update the Progress.
		regressions := []*RegressionAtCommit{}

		commitNumbers := []types.CommitNumber{}
		for id := range foundRegressions {
			commitNumbers = append(commitNumbers, id)
		}
		sort.Sort(types.CommitNumberSlice(commitNumbers))

		for _, commitNumber := range commitNumbers {
			details, err := d.perfGit.CommitFromCommitNumber(ctx, commitNumber)
			if err != nil {
				sklog.Errorf("Failed to look up commit %d: %s", commitNumber, err)
				continue
			}
			regressions = append(regressions, &RegressionAtCommit{
				CID:        details,
				Regression: foundRegressions[commitNumber],
			})
		}
		req.Progress.Results(regressions)
	}

	go func() {
		err := regression.ProcessRegressions(ctx, req, detectorResponseProcessor, d.perfGit, d.shortcutStore, d.dfBuilder, d.paramsProvier(), regression.ExpandBaseAlertByGroupBy, regression.ContinueOnError)
		if err != nil {
			req.Progress.Error(err.Error())
		} else {
			req.Progress.Finished()
		}
	}()

	if err := req.Progress.JSON(w); err != nil {
		sklog.Errorf("Failed to encode paramset: %s", err)
	}
}
