package interceptor

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"strings"

	"github.com/tidbcloud/metrics-integration/global/internal/domain/consts"
	"github.com/tidbcloud/metrics-integration/global/internal/infrastructure/account/accountdb"
	"github.com/tidbcloud/metrics-integration/global/pkg/log"
	"github.com/tidbcloud/pkgv2/auth/auth0"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

func UserPasserUnaryServerInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{},
		info *grpc.UnaryServerInfo, handler grpc.UnaryHandler,
	) (interface{}, error) {
		ctx = passUserIntoContext(ctx)
		return handler(ctx, req)
	}
}

func passUserIntoContext(ctx context.Context) context.Context {
	userValue := getUserValue(ctx)
	if userValue == "" {
		return ctx
	}
	user := &accountdb.User{}
	err := json.Unmarshal([]byte(userValue), user)
	if err != nil {
		log.GetLogger(ctx).Warn("failed to unmarshal user", zap.Error(err))
		return ctx
	}
	ctx = context.WithValue(ctx, auth0.AuthTokenClaimKey, user)
	return ctx
}

func getUserValue(ctx context.Context) string {
	value := FirstHeader(ctx, strings.ToLower(consts.GrpcGatewayMetricsIntegrationUserKey))
	if value != "" {
		decodedBytes, err := base64.StdEncoding.DecodeString(value)
		if err != nil {
			log.GetLogger(ctx).Warn("failed to decode user", zap.Error(err))
			return ""
		}
		return string(decodedBytes)
	}

	value = FirstHeader(ctx, strings.ToLower(string(auth0.AuthTokenClaimKey)))
	if value == "" {
		return ""
	}
	log.GetLogger(ctx).Info("get grpc header AuthTokenClaimKey value")
	return value
}
