package gsresponse

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

	"github.com/stretchr/testify/require"
	"github.com/tech/sendico/pkg/merrors"
	"github.com/tech/sendico/pkg/mservice"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type testRequest struct {
	Value string
}

type testResponse struct {
	Result string
}

func TestUnarySuccess(t *testing.T) {
	logger := zap.NewNop()
	handler := func(ctx context.Context, req *testRequest) Responder[testResponse] {
		require.NotNil(t, req)
		require.Equal(t, "hello", req.Value)
		resp := &testResponse{Result: "ok"}
		return Success(resp)
	}

	unary := Unary(logger, mservice.Type("test"), handler)
	resp, err := unary(context.Background(), &testRequest{Value: "hello"})
	require.NoError(t, err)
	require.NotNil(t, resp)
	require.Equal(t, "ok", resp.Result)
}

func TestAutoMappings(t *testing.T) {
	logger := zap.NewNop()
	service := mservice.Type("test")

	tests := []struct {
		name string
		err  error
		code codes.Code
	}{
		{"invalid_argument", merrors.InvalidArgument("bad"), codes.InvalidArgument},
		{"access_denied", merrors.AccessDenied("object", "action", bson.NilObjectID), codes.PermissionDenied},
		{"not_found", merrors.NoData("missing"), codes.NotFound},
		{"unauthorized", fmt.Errorf("%w: %s", merrors.ErrUnauthorized, "bad"), codes.Unauthenticated},
		{"conflict", merrors.DataConflict("conflict"), codes.Aborted},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			responder := Auto[testResponse](logger, service, tc.err)
			_, err := responder(context.Background())
			require.Error(t, err)
			st, ok := status.FromError(err)
			require.True(t, ok)
			require.Equal(t, tc.code, st.Code())
		})
	}

	responder := Auto[testResponse](logger, service, errors.New("boom"))
	_, err := responder(context.Background())
	require.Error(t, err)
	st, ok := status.FromError(err)
	require.True(t, ok)
	require.Equal(t, codes.Internal, st.Code())
}
