package errors

import (
	"errors"
	"fmt"
	"testing"

	"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/frostfs"
	"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/layer/tree"
	"github.com/stretchr/testify/require"
)

func BenchmarkErrCode(b *testing.B) {
	err := GetAPIError(ErrNoSuchKey)

	for i := 0; i < b.N; i++ {
		if IsS3Error(err, ErrNoSuchKey) {
			_ = err
		}
	}
}

func BenchmarkErrorsIs(b *testing.B) {
	err := GetAPIError(ErrNoSuchKey)

	for i := 0; i < b.N; i++ {
		if errors.Is(err, GetAPIError(ErrNoSuchKey)) {
			_ = err
		}
	}
}

func TestTransformS3Errors(t *testing.T) {
	for _, tc := range []struct {
		name     string
		err      error
		expected ErrorCode
	}{
		{
			name:     "simple std error to internal error",
			err:      errors.New("some error"),
			expected: ErrInternalError,
		},
		{
			name:     "layer access denied error to s3 access denied error",
			err:      frostfs.ErrAccessDenied,
			expected: ErrAccessDenied,
		},
		{
			name:     "wrapped layer access denied error to s3 access denied error",
			err:      fmt.Errorf("wrap: %w", frostfs.ErrAccessDenied),
			expected: ErrAccessDenied,
		},
		{
			name:     "layer node access denied error to s3 access denied error",
			err:      tree.ErrNodeAccessDenied,
			expected: ErrAccessDenied,
		},
		{
			name:     "layer gateway timeout error to s3 gateway timeout error",
			err:      frostfs.ErrGatewayTimeout,
			expected: ErrGatewayTimeout,
		},
		{
			name:     "s3 error to s3 error",
			err:      GetAPIError(ErrInvalidPart),
			expected: ErrInvalidPart,
		},
		{
			name:     "wrapped s3 error to s3 error",
			err:      fmt.Errorf("wrap: %w", GetAPIError(ErrInvalidPart)),
			expected: ErrInvalidPart,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			err := TransformToS3Error(tc.err)
			s3err, ok := err.(Error)
			require.True(t, ok, "error must be s3 error")
			require.Equalf(t, tc.expected, s3err.ErrCode,
				"expected: '%s', got: '%s'",
				GetAPIError(tc.expected).Code, GetAPIError(s3err.ErrCode).Code)
		})
	}
}