package bsv

import (
	"fmt"
	"strings"
)

// Error is the base error type of the library, mirroring the JS errors module.
type Error struct {
	Message string
	Code    string
}

func (e *Error) Error() string { return e.Message }

func newError(code, format string, args ...interface{}) *Error {
	return &Error{Code: code, Message: fmt.Sprintf(format, args...)}
}

// ErrorType wraps errors with a name, mirroring JS error classes.
type ErrorType struct {
	name    string
	message func(args []interface{}) string
}

func (t *ErrorType) New(args ...interface{}) *Error {
	var msg string
	if t.message != nil {
		msg = t.message(args)
	} else {
		msg = fmt.Sprintf("%v", args)
	}
	return &Error{Code: t.name, Message: msg}
}

var (
	// InvalidArgument is thrown when an argument is invalid.
	InvalidArgument = &ErrorType{name: "InvalidArgument", message: func(a []interface{}) string {
		if len(a) == 0 {
			return "Invalid Argument"
		}
		if len(a) == 1 {
			return fmt.Sprintf("Invalid Argument: %v", a[0])
		}
		return fmt.Sprintf("Invalid Argument: %v, %v", a[0], a[1])
	}}
)

// Wrap wraps a generic error into a library Error.
func Wrap(err error) *Error {
	if err == nil {
		return nil
	}
	if e, ok := err.(*Error); ok {
		return e
	}
	return &Error{Message: err.Error()}
}

// ErrorString returns a joined message (used in validation helpers).
func ErrorString(msgs []string) string {
	return strings.Join(msgs, ", ")
}