package middlewares

import (
	"context"
	"net/http"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/tidbcloud/aisupport/packages/sdk-go/infra/errs"
)

func WrapErrorMiddleware() grpc.ServerOption {
	return grpc.ChainUnaryInterceptor(wrapErrorUnaryServerInterceptor())
}

func wrapErrorUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(
		ctx context.Context,
		req any,
		info *grpc.UnaryServerInfo,
		handler grpc.UnaryHandler,
	) (any, error) {
		resp, err := handler(ctx, req)
		if err != nil {
			return resp, wrapRPCError(err)
		}
		return resp, nil
	}
}

func wrapRPCError(err error) error {
	if _, ok := status.FromError(err); ok {
		return err
	}

	if apiErr, ok := errs.AsAPIError(err); ok {
		switch apiErr.ErrCode() {
		case http.StatusBadRequest:
			return status.Error(codes.InvalidArgument, apiErr.ErrMessage())
		case http.StatusUnauthorized:
			return status.Error(codes.Unauthenticated, apiErr.ErrMessage())
		case http.StatusForbidden:
			return status.Error(codes.PermissionDenied, apiErr.ErrMessage())
		case http.StatusNotFound:
			return status.Error(codes.NotFound, apiErr.ErrMessage())
		case http.StatusConflict:
			return status.Error(codes.AlreadyExists, apiErr.ErrMessage())
		case http.StatusPreconditionFailed:
			return status.Error(codes.FailedPrecondition, apiErr.ErrMessage())
		}
	}
	return status.Error(codes.Internal, err.Error())
}
