package metrics

import (
	"fmt"
	"time"

	"github.com/bazelbuild/continuous-integration/metrics/clients"
	"github.com/bazelbuild/continuous-integration/metrics/data"
)

type PipelinePerformance struct {
	client      clients.BuildkiteClient
	pipelines   []*data.PipelineID
	columns     []Column
	lastNBuilds int
}

func (pp *PipelinePerformance) Name() string {
	return "pipeline_performance"
}

func (pp *PipelinePerformance) Columns() []Column {
	return pp.columns
}

func (*PipelinePerformance) Type() MetricType {
	return BuildBasedMetric
}

func (*PipelinePerformance) RelevantDelta() int {
	return 100 // builds
}

func (pp *PipelinePerformance) Collect() (data.DataSet, error) {
	result := &pipelinePerformanceSet{headers: GetColumnNames(pp.columns)}
	for _, pipeline := range pp.pipelines {
		builds, err := pp.client.GetMostRecentBuilds(pipeline, pp.lastNBuilds)
		if err != nil {
			return nil, fmt.Errorf("Cannot collect performance statistics for pipeline %s: %v", pipeline, err)
		}
		for _, build := range builds {
			skippedTasks := getSkippedTasks(build)
			for _, job := range build.Jobs {
				if !isFinishedWorkerTask(job) {
					continue
				}
				row := &pipelinePerformanceRow{org: pipeline.Org,
					pipeline:        pipeline.Slug,
					build:           *build.Number,
					job:             *job.Name,
					creationTime:    job.RunnableAt.Time,
					waitTimeSeconds: getDifferenceSeconds(job.RunnableAt, job.StartedAt),
					runTimeSeconds:  getDifferenceSeconds(job.StartedAt, job.FinishedAt),
					skippedTasks:    skippedTasks,
				}
				result.rows = append(result.rows, row)
			}
		}
	}
	return result, nil
}

// CREATE TABLE pipeline_performance (org VARCHAR(255), pipeline VARCHAR(255), build INT, job VARCHAR(255), creation_time DATETIME, wait_time_seconds FLOAT, run_time_seconds FLOAT, skipped_tasks VARCHAR(255), PRIMARY KEY(org, pipeline, build, job));
func CreatePipelinePerformance(client clients.BuildkiteClient, lastNBuilds int, pipelines ...*data.PipelineID) *PipelinePerformance {
	columns := []Column{Column{"org", true}, Column{"pipeline", true}, Column{"build", true}, Column{"job", true}, Column{"creation_time", false}, Column{"wait_time_seconds", false}, Column{"run_time_seconds", false}, Column{"skipped_tasks", false}}
	return &PipelinePerformance{client: client, pipelines: pipelines, columns: columns, lastNBuilds: lastNBuilds}
}

type pipelinePerformanceRow struct {
	org             string
	pipeline        string
	build           int
	job             string
	creationTime    time.Time
	waitTimeSeconds float64
	runTimeSeconds  float64
	skippedTasks    string
}

type pipelinePerformanceSet struct {
	headers []string
	rows    []*pipelinePerformanceRow
}

func (s *pipelinePerformanceSet) GetData() *data.LegacyDataSet {
	rawSet := data.CreateDataSet(s.headers)
	for _, row := range s.rows {
		rawRow := []interface{}{row.org, row.pipeline, row.build, row.job, row.creationTime, row.waitTimeSeconds, row.runTimeSeconds, row.skippedTasks}
		rawSet.Data = append(rawSet.Data, rawRow)
	}
	return rawSet
}
