package errs

import "errors"

type aggregateError struct {
	errors []error
}

func FromMany(errors ...error) error {
	n := 0
	for _, err := range errors {
		if err != nil {
			n++
		}
	}
	if n == 0 {
		return nil
	}
	aggregateErr := &aggregateError{
		errors: make([]error, 0, n),
	}
	for _, err := range errors {
		if err != nil {
			aggregateErr.errors = append(aggregateErr.errors, err)
		}
	}
	return aggregateErr
}

func (ce *aggregateError) Error() string {
	var b []byte
	for i, err := range ce.errors {
		if i > 0 {
			b = append(b, '\n')
		}
		b = append(b, err.Error()...)
	}
	return string(b)
}

func (ce *aggregateError) Unwrap() error {
	return errorChain(ce.errors)
}

// Represents chained list of errors.
// Implements Error interface so that chain of errors
// can correctly work with errors.Is/As method
type errorChain []error

func (ec errorChain) Error() string {
	return ec[0].Error()
}

func (ec errorChain) Unwrap() error {
	if len(ec) == 1 {
		return nil
	}

	return ec[1:]
}

func (ec errorChain) As(target interface{}) bool {
	return errors.As(ec[0], target)
}

func (ec errorChain) Is(target error) bool {
	return errors.Is(ec[0], target)
}