package tree

import (
	"context"
	"fmt"
	"strings"

	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/common"
	"git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-cli/internal/commonflags"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/network"
	"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/tree"
	metrics "git.frostfs.info/TrueCloudLab/frostfs-observability/metrics/grpc"
	tracing "git.frostfs.info/TrueCloudLab/frostfs-observability/tracing/grpc"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

// _client returns grpc Tree service client. Should be removed
// after making Tree API public.
func _client() (tree.TreeServiceClient, error) {
	var netAddr network.Address

	rpcEndpoint := viper.GetString(commonflags.RPC)
	if rpcEndpoint == "" {
		return nil, fmt.Errorf("%s is not defined", commonflags.RPC)
	}

	err := netAddr.FromString(rpcEndpoint)
	if err != nil {
		return nil, err
	}

	opts := []grpc.DialOption{
		grpc.WithChainUnaryInterceptor(
			metrics.NewUnaryClientInterceptor(),
			tracing.NewUnaryClientInteceptor(),
		),
		grpc.WithChainStreamInterceptor(
			metrics.NewStreamClientInterceptor(),
			tracing.NewStreamClientInterceptor(),
		),
		grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
	}

	if !strings.HasPrefix(netAddr.URIAddr(), "grpcs:") {
		opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
	}

	cc, err := grpc.NewClient(netAddr.URIAddr(), opts...)
	return tree.NewTreeServiceClient(cc), err
}

func contextWithTimeout(cmd *cobra.Command) (context.Context, context.CancelFunc) {
	if timeout := viper.GetDuration(commonflags.Timeout); timeout > 0 {
		common.PrintVerbose(cmd, "Set request timeout to %s.", timeout)
		return context.WithTimeout(cmd.Context(), timeout)
	}
	return context.WithTimeout(cmd.Context(), commonflags.TimeoutDefault)
}