package cli

import (
	"context"
	"fmt"
	"strings"
	"sync"
	"time"

	"github.com/sercand/kuberesolver/v5"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	tigrpc "github.com/tidbcloud/tiinf/transport/tigrpc/client"

	"github.com/tidbcloud/tidb-management-service/serverless-global-service/pkg/config"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	grpcutil "github.com/tidbcloud/tidb-management-service/utilities/grpc"
)

var (
	accountSvcOnce sync.Once
	accountSvcCli  account.AccountAPIServiceClient
)

func getAccountSvcClient() account.AccountAPIServiceClient {
	accountSvcOnce.Do(func() {
		addr := config.Global().ServerConfig.DependentSvcAddresses.AccountProviderSvcAddr
		timeoutMs := config.Global().ServerConfig.DependentSvcAddresses.WaitTimeoutInMilliSec
		opts := []tigrpc.Option{
			tigrpc.WithPrometheus(),
			tigrpc.WithTracing(),
			tigrpc.WithUnaryInterceptors(
				grpcutil.ClientPayloadLogInterceptor,
				grpcutil.TimeoutInterceptor(time.Duration(timeoutMs)*time.Millisecond),
			),
		}
		if strings.HasPrefix(addr, "kubernetes://") {
			kuberesolver.RegisterInCluster()
			opts = append(opts, tigrpc.WithLoadBalance())
		}
		conn, err := tigrpc.NewClientConn(addr, opts...)
		if err != nil {
			panic(fmt.Sprintf("dial account-provider-svc: %s", err))
		}

		accountSvcCli = account.NewAccountAPIServiceClient(conn)
	})

	return accountSvcCli
}

func GetDBUsers(ctx context.Context, req *account.GetDBUsersReq) (*account.GetDBUsersResp, bizerr.BizError) {
	client := getAccountSvcClient()

	resp, e := client.GetDBUsers(ctx, req)
	if e != nil {
		return resp, bizerr.WrapGrpcError(e, "GetInitialTiDBUsers")
	}
	if resp.BaseResp.ErrCode != 0 {
		return resp, bizerr.New(
			bizerr.ErrCodeSvcAccount,
			"code=%d, msg=%s",
			resp.BaseResp.ErrCode,
			resp.BaseResp.ErrMsg,
		)
	}

	return resp, nil
}

func IsHitFeatureFlag(ctx context.Context, req *account.HitFeatureFlagReq) (bool, error) {
	client := getAccountSvcClient()

	resp, e := client.IsHitFeatureFlag(ctx, req)
	if e != nil {
		return false, bizerr.WrapGrpcError(e, "IsHitFeatureFlag")
	}
	if resp.BaseResp != nil && resp.BaseResp.ErrCode != 0 {
		return false, bizerr.New(
			bizerr.ErrCodeSvcAccount,
			"code=%d, msg=%s",
			resp.BaseResp.ErrCode,
			resp.BaseResp.ErrMsg,
		)
	}

	return resp.IsHit, nil
}
