package bizerr

import (
	"errors"
	"fmt"

	"github.com/go-sql-driver/mysql"
	"gorm.io/gorm"
)

const (
	mysqlErrCodeDuplicatedKey = 1062
)

func ParseGormErr2code(err error) ErrCode {
	if err == nil {
		return ErrCodeOK
	}
	if be, ok := err.(BizError); ok {
		return be.ErrCode()
	}

	if errors.Is(err, gorm.ErrRecordNotFound) {
		return ErrCodeRecordNotFound
	}

	var mysqlErr *mysql.MySQLError
	if errors.As(err, &mysqlErr) && mysqlErr.Number == mysqlErrCodeDuplicatedKey {
		return ErrCodeRecordExist
	}
	return ErrCodeDB
}

func WrapGormError(err error, format string, args ...interface{}) BizError {
	if err == nil {
		return nil
	}
	if be, ok := err.(BizError); ok {
		return be
	}

	return New(ParseGormErr2code(err), "%s: %s", fmt.Sprintf(format, args...), err)
}

func WrapGrpcError(err error, format string, args ...interface{}) BizError {
	return WrapErrorWithCode(err, ErrCodeGRPC, format, args...)
}

func WrapError(err error, format string, args ...interface{}) BizError {
	return WrapErrorWithCode(err, ErrCodeUnknown, format, args...)
}

func WrapErrorWithCode(err error, code ErrCode, format string, args ...interface{}) BizError {
	if err == nil {
		return nil
	}
	if be, ok := err.(BizError); ok {
		return be
	}
	return New(code, "%s: %s", fmt.Sprintf(format, args...), err)
}

func Pipeline(fns ...func() error) error {
	for _, each := range fns {
		if err := each(); err != nil {
			return err
		}
	}
	return nil
}

func Message(err error) string {
	if err == nil {
		return ""
	}
	if be, ok := err.(BizError); ok {
		return be.ErrMsg()
	}
	return err.Error()
}
