package globalnextgencli

import (
	"errors"
	"strings"
	"time"

	"github.com/sercand/kuberesolver/v5"
	tigrpcclient "github.com/tidbcloud/tiinf/transport/tigrpc/client"
	"google.golang.org/grpc"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/domain/adapter/nextgenglobal"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/config"
	grpcutil "github.com/tidbcloud/tidb-management-service/utilities/grpc"
)

type TimeoutCallOption struct {
	grpc.EmptyCallOption
}

func NewClient(cfg *config.NextGenGlobalService) (nextgenglobal.NextGenGlobal, error) {
	if cfg == nil {
		return nil, errors.New("config is nil")
	}

	// if cfg.Local {
	// 	return &fakeImpl{}, nil
	// }

	var (
		conn *grpc.ClientConn
		err  error
	)

	interceptors := tigrpcclient.WithUnaryInterceptors(
		grpcutil.AppendRequestMetaInterceptor,
		grpcutil.ClientPayloadLogInterceptor,
		grpcutil.TimeoutInterceptor(time.Duration(cfg.WaitTimeoutInMilliSec)*time.Millisecond),
	)

	opts := []tigrpcclient.Option{tigrpcclient.WithPrometheus(), tigrpcclient.WithTracing(), interceptors}
	if strings.HasPrefix(cfg.Url, "kubernetes://") {
		kuberesolver.RegisterInCluster()
		opts = append(opts, tigrpcclient.WithLoadBalance())
	}

	// More about timeout:
	// We have a server option to set a timeout on connection establishment: https://pkg.go.dev/google.golang.org/grpc#ConnectionTimeout
	//
	// We have ways to configure keepalive parameters on the server: https://pkg.go.dev/google.golang.org/grpc@v1.43.0/keepalive#ServerParameters
	//
	// And if we wish to set timeouts on a per-RPC level, you could register a server interceptor using https://pkg.go.dev/google.golang.org/grpc#UnaryInterceptor and create a new context in there with a different timeout and pass it to the handler.

	if conn, err = tigrpcclient.NewClientConn(cfg.Url, opts...); err != nil {
		return nil, err
	}
	clusterCli := globalngv1.NewClusterServiceClient(conn)
	byocVpcPeeringCli := globalngv1.NewByocVpcPeeringServiceClient(conn)
	regionCli := globalngv1.NewRegionServiceClient(conn)
	publicConnectionSettingCli := globalngv1.NewPublicConnectionSettingServiceClient(conn)
	privateEndpointConnectionCli := globalngv1.NewPrivateLinkConnectionServiceClient(conn)
	backupCli := globalngv1.NewBackupServiceClient(conn)
	exportCli := globalngv1.NewExportServiceClient(conn)
	auditLogCli := globalngv1.NewDatabaseAuditLogServiceClient(conn)
	logRedactionPolicyCli := globalngv1.NewLogRedactionPolicyServiceClient(conn)
	planReplayerCli := globalngv1.NewPlanReplayerServiceClient(conn)
	resourcePoolCli := globalngv1.NewResourcePoolServiceClient(conn)
	rcuQuotaCli := globalngv1.NewRcuQuotaServiceClient(conn)
	cmekCli := globalngv1.NewCustomerManagedEncryptionKeyServiceClient(conn)
	reservedCapacityTemplateCli := globalngv1.NewReservedCapacityTemplateServiceClient(conn)

	c := clientImpl{
		clusterCli:                   clusterCli,
		byocVpcPeeringCli:            byocVpcPeeringCli,
		regionCli:                    regionCli,
		publicConnectionSettingCli:   publicConnectionSettingCli,
		privateEndpointConnectionCli: privateEndpointConnectionCli,
		backupCli:                    backupCli,
		exportCli:                    exportCli,
		auditlogCli:                  auditLogCli,
		logRedactionPolicyCli:        logRedactionPolicyCli,
		planReplayerCli:              planReplayerCli,
		resourcePoolCli:              resourcePoolCli,
		rcuQuotaCli:                  rcuQuotaCli,
		cmekCli:                      cmekCli,
		reservedCapacityTemplateCli:  reservedCapacityTemplateCli,
	}
	return &c, nil
}
