package buildkite

import (
	"fmt"
	"sort"
	"strings"
)

type pipelinesDisplayData struct {
	buildsForPipeline map[string][]Build
	orderedPipelines  []string
}

func (data *pipelinesDisplayData) Content() string {
	maxPipelineLength := getLongestLength(data.orderedPipelines)

	str := ""
	for _, pipeline := range data.orderedPipelines {
		str += fmt.Sprintf("[white]%s", padRight(pipeline, maxPipelineLength))
		for _, build := range data.buildsForPipeline[pipeline] {
			str += fmt.Sprintf("  [%s]%s[white]", buildColor(build.State), build.Branch)
		}
		str += "\n"
	}

	return str
}

func NewPipelinesDisplayData(builds []Build) pipelinesDisplayData {
	grouped := make(map[string][]Build)

	for _, build := range builds {
		if _, ok := grouped[build.Pipeline.Slug]; ok {
			grouped[build.Pipeline.Slug] = append(grouped[build.Pipeline.Slug], build)
		} else {
			grouped[build.Pipeline.Slug] = []Build{}
			grouped[build.Pipeline.Slug] = append(grouped[build.Pipeline.Slug], build)
		}
	}

	orderedPipelines := make([]string, len(grouped))
	i := 0
	for pipeline := range grouped {
		orderedPipelines[i] = pipeline
		i++
	}
	sort.Strings(orderedPipelines)

	name := func(b1, b2 *Build) bool {
		return b1.Branch < b2.Branch
	}
	for _, builds := range grouped {
		ByBuild(name).Sort(builds)
	}

	return pipelinesDisplayData{
		buildsForPipeline: grouped,
		orderedPipelines:  orderedPipelines,
	}
}

type ByBuild func(b1, b2 *Build) bool

func (by ByBuild) Sort(builds []Build) {
	sorter := &buildSorter{
		builds: builds,
		by:     by,
	}
	sort.Sort(sorter)
}

type buildSorter struct {
	builds []Build
	by     func(b1, b2 *Build) bool
}

func (bs *buildSorter) Len() int {
	return len(bs.builds)
}

func (bs *buildSorter) Swap(i, j int) {
	bs.builds[i], bs.builds[j] = bs.builds[j], bs.builds[i]
}

func (bs *buildSorter) Less(i, j int) bool {
	return bs.by(&bs.builds[i], &bs.builds[j])
}

func getLongestLength(strs []string) int {
	longest := 0

	for _, str := range strs {
		if len(str) > longest {
			longest = len(str)
		}
	}

	return longest
}

func padRight(text string, length int) string {
	padLength := length - len(text)

	if padLength <= 0 {
		return text[:length]
	}

	return text + strings.Repeat(" ", padLength)
}

func buildColor(state string) string {
	switch state {
	case "passed":
		return "green"
	case "failed":
		return "red"
	default:
		return "yellow"
	}
}
