package grpccorrelation

import (
	"context"

	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	"gitlab.com/gitlab-org/labkit/correlation"
	"google.golang.org/grpc"
	"google.golang.org/grpc/metadata"
)

func extractFromContext(ctx context.Context) context.Context {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return ctx
	}

	// Extract correlation_id
	values := md.Get(metadataCorrelatorKey)
	if len(values) > 0 {
		ctx = correlation.ContextWithCorrelation(ctx, values[0])
	}

	// Extract client name
	clientNames := md.Get(metadataClientNameKey)
	if len(clientNames) > 0 {
		ctx = correlation.ContextWithClientName(ctx, clientNames[0])
	}

	return ctx
}

// UnaryServerCorrelationInterceptor propagates Correlation-IDs from incoming upstream services
func UnaryServerCorrelationInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		ctx = extractFromContext(ctx)
		return handler(ctx, req)
	}
}

// StreamServerCorrelationInterceptor propagates Correlation-IDs from incoming upstream services
func StreamServerCorrelationInterceptor() grpc.StreamServerInterceptor {
	return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
		wrapped := grpc_middleware.WrapServerStream(ss)
		wrapped.WrappedContext = extractFromContext(ss.Context())

		return handler(srv, wrapped)
	}
}
