package interceptor

import (
	"context"
	"runtime/debug"

	"github.com/getsentry/sentry-go"
	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/pingcap/errcode"
	"github.com/pingcap/errors"
	bizerr_wrapper "github.com/tidbcloud/metrics-integration/global/pkg/bizerr-wrapper"
	"github.com/tidbcloud/metrics-integration/global/pkg/log"
	"google.golang.org/grpc"
)

func RecoverPanicInterceptor() grpc.UnaryServerInterceptor {
	return grpc_recovery.UnaryServerInterceptor(grpc_recovery.WithRecoveryHandlerContext(panicHandler))
}

func panicHandler(ctx context.Context, p interface{}) error {
	logger := log.GetLogger(ctx)
	err, ok := p.(error)
	if ok && errors.HasStack(err) {
		logger.Sugar().Warnf("panic, err: %s, stack: %s", err, errors.GetStackTracer(err).StackTrace())
	} else {
		logger.Sugar().Warnf("panic, err: %s, stack: %s", p, debug.Stack())
	}

	// I don't know why the usual stack trace is not working
	// So putting debug.Stack() into the message for now
	if !ok {
		return bizerr_wrapper.NewInternalErr("%+vn%s", p, debug.Stack())
	}

	sentry.CurrentHub().Recover(err)
	return errcode.NewInternalErr(err)
}
