package utils

import (
	"fmt"
	"strings"
	"sync"
)

// ErrGroup accumulates multiple errors
// and produces single error message.
type ErrGroup struct {
	mu   sync.Mutex
	errs []error
}

// Add adds a new error to group.
// Is thread-safe.
func (eg *ErrGroup) Add(err error) {
	eg.mu.Lock()
	eg.errs = append(eg.errs, err)
	eg.mu.Unlock()
}

// Err checks if group contains at least
// one error.
func (eg *ErrGroup) Err() error {
	if eg == nil {
		return nil
	}

	eg.mu.Lock()
	defer eg.mu.Unlock()
	if len(eg.errs) == 0 {
		return nil
	}
	return eg
}

// Error satisfies Error interface
func (eg *ErrGroup) Error() string {
	eg.mu.Lock()
	defer eg.mu.Unlock()

	if len(eg.errs) == 0 {
		return ""
	}
	var b strings.Builder
	fmt.Fprintf(&b, "errors(%d): ", len(eg.errs))
	for i, err := range eg.errs {
		b.WriteString(err.Error())
		if i != len(eg.errs)-1 {
			b.WriteString("\n")
		}
	}
	return b.String()
}