package knife

import (
	"context"

	"github.com/samber/lo"
	"github.com/tidbcloud/pkgv2/bizerr"
	pkglog "github.com/tidbcloud/pkgv2/log"
	"go.uber.org/zap"
	"google.golang.org/grpc"
)

type DegradationConfig struct {
	Enable             bool           `mapstructure:"enable"`
	DisabledRPCMethods []string       `mapstructure:"disabled_rpc_methods"`
	DisabledWorkers    []string       `mapstructure:"disabled_workers"`
	DegradationErrCode bizerr.ErrCode `mapstructure:"degradation_err_code" default:"49900008"`
	DegradationErrMsg  string         `mapstructure:"degradation_err_msg" default:"Sorry, the Management Console are temporarily unavailable due to maintenance. Please check back later. Thank you for your understanding."`
}

func WorkerDegraded(workerName string, conf DegradationConfig) bool {
	if !conf.Enable {
		return false
	}
	if lo.Contains(conf.DisabledWorkers, workerName) {
		return true
	}
	return false
}

func RPCMethodDegraded(methodName string, conf DegradationConfig) bool {
	if !conf.Enable {
		return false
	}
	if lo.Contains(conf.DisabledRPCMethods, methodName) {
		return true
	}
	return false
}

func DegradationInterceptor(confGetter func() DegradationConfig) grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
		method := ""
		if m, ok := grpc.Method(ctx); ok {
			method = m
		}
		logger := pkglog.WithContextL(ctx).With(zap.String("methodName", method))

		conf := confGetter()
		if RPCMethodDegraded(method, conf) {
			logger.Info("this method is degraded, return immediately")
			return nil, bizerr.New(conf.DegradationErrCode, conf.DegradationErrMsg)
		}
		return handler(ctx, req)
	}
}
