package frostfs

import (
	"context"
	"errors"
	"fmt"
	"testing"
	"time"

	"git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/handler"
	apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func TestHandleObjectError(t *testing.T) {
	msg := "some msg"

	t.Run("nil error", func(t *testing.T) {
		err := handleObjectError(msg, nil)
		require.Nil(t, err)
	})

	t.Run("simple access denied", func(t *testing.T) {
		reason := "some reason"
		inputErr := new(apistatus.ObjectAccessDenied)
		inputErr.WriteReason(reason)

		err := handleObjectError(msg, inputErr)
		require.ErrorIs(t, err, handler.ErrAccessDenied)
		require.Contains(t, err.Error(), reason)
		require.Contains(t, err.Error(), msg)
	})

	t.Run("access denied - quota reached", func(t *testing.T) {
		reason := "Quota limit reached"
		inputErr := new(apistatus.ObjectAccessDenied)
		inputErr.WriteReason(reason)

		err := handleObjectError(msg, inputErr)
		require.ErrorIs(t, err, handler.ErrQuotaLimitReached)
		require.Contains(t, err.Error(), reason)
		require.Contains(t, err.Error(), msg)
	})

	t.Run("simple timeout", func(t *testing.T) {
		inputErr := errors.New("timeout")

		err := handleObjectError(msg, inputErr)
		require.ErrorIs(t, err, handler.ErrGatewayTimeout)
		require.Contains(t, err.Error(), inputErr.Error())
		require.Contains(t, err.Error(), msg)
	})

	t.Run("deadline exceeded", func(t *testing.T) {
		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
		defer cancel()
		<-ctx.Done()

		err := handleObjectError(msg, ctx.Err())
		require.ErrorIs(t, err, handler.ErrGatewayTimeout)
		require.Contains(t, err.Error(), ctx.Err().Error())
		require.Contains(t, err.Error(), msg)
	})

	t.Run("grpc deadline exceeded", func(t *testing.T) {
		inputErr := fmt.Errorf("wrap grpc error: %w", status.Error(codes.DeadlineExceeded, "error"))

		err := handleObjectError(msg, inputErr)
		require.ErrorIs(t, err, handler.ErrGatewayTimeout)
		require.Contains(t, err.Error(), inputErr.Error())
		require.Contains(t, err.Error(), msg)
	})

	t.Run("unknown error", func(t *testing.T) {
		inputErr := errors.New("unknown error")

		err := handleObjectError(msg, inputErr)
		require.ErrorIs(t, err, inputErr)
		require.Contains(t, err.Error(), msg)
	})
}