package clusters

import (
	"sync"

	"code.justin.tv/d8a/buddy/lib/config"
	multierror "github.com/hashicorp/go-multierror"
)

type processOutput struct {
	result interface{}
	err    error
}

func ProcessInParallel(clusters config.ClusterList, processCluster func(cluster *config.Cluster) (interface{}, error), processResult func(result interface{}, err error) error) error {
	combinedErr := new(multierror.Error)
	var allClustersDone sync.WaitGroup
	results := make(chan *processOutput, len(clusters))

	for _, cluster := range clusters {
		allClustersDone.Add(1)
		go func(cluster *config.Cluster) {
			defer allClustersDone.Done()

			result, err := processCluster(cluster)
			results <- &processOutput{
				result: result,
				err:    err,
			}
		}(cluster)
	}

	allClustersDone.Wait()
	close(results)

	for output := range results {
		err := processResult(output.result, output.err)

		if err != nil {
			combinedErr = multierror.Append(combinedErr, err)
		}
	}

	return combinedErr.ErrorOrNil()
}
