// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package cli

import (
	"context"
	"fmt"
	"strings"

	"github.com/peterbourgon/ff/v3/ffcli"
	"tailscale.com/atomicfile"
)

var metricsCmd = &ffcli.Command{
	Name:      "metrics",
	ShortHelp: "Show " + currentProductName() + " metrics",
	LongHelp: strings.TrimSpace(fmt.Sprintf(`

The '%s metrics' command shows %s user-facing metrics (as opposed
to internal metrics printed by '%s debug metrics').

For more information about %s metrics, refer to
https://tailscale.com/s/client-metrics

`, currentCLIName(), currentProductName(), currentCLIName(), currentProductName())),
	ShortUsage: currentCLIName() + " metrics <subcommand> [flags]",
	UsageFunc:  usageFuncNoDefaultValues,
	Exec:       runMetricsNoSubcommand,
	Subcommands: []*ffcli.Command{
		{
			Name:       "print",
			ShortUsage: currentCLIName() + " metrics print",
			Exec:       runMetricsPrint,
			ShortHelp:  "Print current metric values in Prometheus text format",
		},
		{
			Name:       "write",
			ShortUsage: currentCLIName() + " metrics write <path>",
			Exec:       runMetricsWrite,
			ShortHelp:  "Write metric values to a file",
			LongHelp: strings.TrimSpace(fmt.Sprintf(`

The '%s metrics write' command writes metric values to a text file provided as its
only argument. It's meant to be used alongside Prometheus node exporter, allowing %s
metrics to be consumed and exported by the textfile collector.

As an example, to export %s metrics on an Ubuntu system running node exporter, you
can regularly run '%s metrics write /var/lib/prometheus/node-exporter/tailscaled.prom'
using cron or a systemd timer.

	`, currentCLIName(), currentProductName(), currentProductName(), currentCLIName())),
		},
	},
}

// runMetricsNoSubcommand prints metric values if no subcommand is specified.
func runMetricsNoSubcommand(ctx context.Context, args []string) error {
	if len(args) > 0 {
		return fmt.Errorf("%s metrics: unknown subcommand: %s", currentCLIName(), args[0])
	}

	return runMetricsPrint(ctx, args)
}

// runMetricsPrint prints metric values to stdout.
func runMetricsPrint(ctx context.Context, args []string) error {
	out, err := localClient.UserMetrics(ctx)
	if err != nil {
		return err
	}
	Stdout.Write(out)
	return nil
}

// runMetricsWrite writes metric values to a file.
func runMetricsWrite(ctx context.Context, args []string) error {
	if len(args) != 1 {
		return fmt.Errorf("usage: %s metrics write <path>", currentCLIName())
	}
	path := args[0]
	out, err := localClient.UserMetrics(ctx)
	if err != nil {
		return err
	}
	return atomicfile.WriteFile(path, out, 0644)
}
