package cmd

import (
	"io"
	"strings"
	"testing"

	"github.com/tidbcloud/clinic-cli/internal/config"
)

func TestGeneratedRootHelpRendersPrimaryUsage(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("root help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"--help"}, &stdout); err != nil {
		t.Fatalf("run(--help) error = %v", err)
	}

	assertContainsAll(t, stdout.String(), []string{
		"clinic wraps the Clinic API for TiDB Cloud operations.",
		"Usage:",
		"clinic [flags]",
		"Available Commands:",
		"version",
		"auth",
		"Global Flags:",
		"Select the runtime environment for this invocation only.",
		"Print runtime resolution diagnostics and executed API requests to stderr.",
		"Select an env-local profile for this invocation only.",
	})
	assertContainsNone(t, stdout.String(), []string{"Global options:"})
}

func TestGeneratedRootHelpIncludesGlobalFlags(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("root help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{
			"auth": func(*RuntimeContext, []string, io.Writer) error {
				t.Fatal("root help should not run handlers")
				return nil
			},
		},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"--help"}, &stdout); err != nil {
		t.Fatalf("run(--help) error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"clinic wraps the Clinic API for TiDB Cloud operations.",
		"Usage:",
		"clinic [flags]",
		"Available Commands:",
		"auth",
		"version",
		"Global Flags:",
		"--env string",
		"Select the runtime environment for this invocation only.",
		"--profile string",
		"Select an env-local profile for this invocation only.",
		"--verbose",
		"Print runtime resolution diagnostics and executed API requests to stderr.",
	})
	assertContainsNone(t, output, []string{"Global options:"})
}

func TestVersionGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := versionCommandHandler(nil, []string{"--help"}, &stdout); err != nil {
		t.Fatalf("version help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Show clinic CLI version information.",
		"Usage:",
		"version",
		"Output:",
		"Plain-text version string.",
	})
}

func TestCompletionGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := completionCommandHandler(nil, []string{"--help"}, &stdout); err != nil {
		t.Fatalf("completion help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Generate shell completion scripts.",
		"Usage:",
		"completion <bash|zsh|fish|powershell>",
		"Arguments:",
		"Shell type to generate completion script for.",
		"Examples:",
		"clinic completion bash",
	})
}

func TestAuthGeneratedHelp(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("auth help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"auth", "set-url", "--help"}, &stdout); err != nil {
		t.Fatalf("auth set-url help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Set the Clinic base URL for one environment.",
		"Usage:",
		"clinic auth set-url",
		"Flags:",
		"--env string",
		"Target environment. Defaults to selected environment.",
		"--url string",
		"Base URL. Must use http or https.",
		"Global Flags:",
		"--profile string",
		"--verbose",
		"Examples:",
	})
	assertContainsNone(t, output, []string{"Optional flags:", "Required flags:"})
}

func TestEnvGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := envCommandHandler(nil, []string{"--help"}, &stdout); err != nil {
		t.Fatalf("env help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Inspect and switch configured environments.",
		"Usage:",
		"env",
		"Available Commands:",
		"use",
		"current",
		"list",
	})
	assertContainsNone(t, output, []string{"Subcommands:"})

	stdout.Reset()
	if err := envCommandHandler(nil, []string{"use", "--help"}, &stdout); err != nil {
		t.Fatalf("env use help error = %v", err)
	}

	output = stdout.String()
	assertContainsAll(t, output, []string{
		"Persist the active environment in local config.",
		"Usage:",
		"env use <prod|staging|dev>",
		"Arguments:",
		"Environment to make active.",
		"Examples:",
	})
}

func TestProfileGeneratedHelp(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("profile help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"profile", "--help"}, &stdout); err != nil {
		t.Fatalf("profile help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Manage env-scoped runtime profiles and defaults.",
		"Usage:",
		"clinic profile",
		"Available Commands:",
		"list",
		"current",
		"open",
		"use",
		"set",
		"delete",
		"Global Flags:",
		"--env string",
		"--profile string",
		"--verbose",
		"Examples:",
	})
	assertContainsNone(t, output, []string{"Subcommands:"})
}

func TestProfileSetGeneratedHelpIncludesCurrentAliasNote(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("profile set help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"profile", "set", "--help"}, &stdout); err != nil {
		t.Fatalf("profile set help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Create or update a profile in the selected environment.",
		"Usage:",
		"clinic profile set <name>",
		"Flags:",
		"--cluster-id string",
		"--start string",
		"--end string",
		"Use reserved name \"current\"",
		"\"current\" cannot be used as a literal profile record name",
		"Global Flags:",
		"--env string",
		"--profile string",
		"--verbose",
	})
	assertContainsNone(t, output, []string{"Optional flags:", "Cluster selection:"})
}

func TestSwitchGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := switchCommandHandler(nil, []string{"--help"}, &stdout); err != nil {
		t.Fatalf("switch help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Switch active environment and optionally active profile in one command.",
		"Usage:",
		"switch <prod|staging|dev> [profile-name]",
		"Behavior:",
		"When profile is omitted",
		"Output:",
		"Examples:",
	})
}

func TestClusterGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := clusterCommandHandler(nil, []string{"search-id", "--help"}, &stdout); err != nil {
		t.Fatalf("cluster search-id help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Search clusters by exact cluster ID via dashboard list API.",
		"Usage:",
		"cluster search-id",
		"Flags:",
		"--cluster-id string",
		"--show-deleted",
		"--limit int",
		"--page int",
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:"})
}

func TestClusterSearchGeneratedHelpIncludesDeployTypeValues(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := clusterCommandHandler(nil, []string{"search", "--help"}, &stdout); err != nil {
		t.Fatalf("cluster search help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Known deploy_type_v2 values:",
		"premium resource pool",
		"premium reserved resource pool",
		"essential v2 resource pool",
		"byoc resource pool",
		"Values are matched verbatim (case- and space-sensitive).",
		"--deploy-type string",
	})
}

func TestDataGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := dataCommandHandler(nil, []string{"query", "--help"}, &stdout); err != nil {
		t.Fatalf("data query help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Execute SQL through data-proxy.",
		"Usage:",
		"data query",
		"Flags:",
		"--cluster-id string",
		"--sql string",
		"--timeout int",
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:"})
}

func TestEventsGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := eventsCommandHandler(nil, []string{"list", "--help"}, &stdout); err != nil {
		t.Fatalf("events list help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"List activity events for a cluster.",
		"Usage:",
		"events list",
		"now-<duration>",
		"defaults to local",
		"epoch in s/ms/ns",
		"Flags:",
		"--cluster-id string",
		"--start string",
		"--end string",
		"--severity int",
		"--limit int",
		"--cursor string",
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:"})
}

func TestRawGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := rawCommandHandler(nil, []string{"request", "--help"}, &stdout); err != nil {
		t.Fatalf("raw request help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Send a raw API request.",
		"Usage:",
		"raw request",
		"Flags:",
		"--method string",
		"--path string",
		"--query stringArray",
		"--header stringArray",
		"--body string",
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:"})
}

func TestMigratedRootCommandHelpIncludesGlobalFlags(t *testing.T) {
	t.Parallel()

	runner := rootRunner{
		loadConfig: func() (*config.Config, error) {
			t.Fatal("migrated command help should not load config")
			return nil, nil
		},
		handlers: map[string]commandHandler{},
	}

	var stdout strings.Builder
	if err := runner.run([]string{"env", "use", "--help"}, &stdout); err != nil {
		t.Fatalf("env use root help error = %v", err)
	}

	assertContainsAll(t, stdout.String(), []string{
		"Usage:",
		"clinic env use <prod|staging|dev>",
		"Global Flags:",
		"--env string",
		"--profile string",
		"--verbose",
	})
}

func TestCommandHelpRendersForEveryCommandFamily(t *testing.T) {
	t.Parallel()

	testCases := []struct {
		name    string
		handler commandHandler
		args    []string
		want    []string
	}{
		{
			name:    "auth",
			handler: authCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"auth",
				"Available Commands:",
				"set-key",
			},
		},
		{
			name:    "env",
			handler: envCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"env",
				"Available Commands:",
				"use",
			},
		},
		{
			name:    "profile",
			handler: profileCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"profile",
				"Available Commands:",
				"set",
			},
		},
		{
			name:    "switch",
			handler: switchCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"switch <prod|staging|dev> [profile-name]",
				"Switch active environment",
			},
		},
		{
			name:    "completion",
			handler: completionCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"completion <bash|zsh|fish|powershell>",
				"Generate shell completion scripts",
			},
		},
		{
			name:    "cluster",
			handler: clusterCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"cluster",
				"Available Commands:",
				"search",
			},
		},
		{
			name:    "data",
			handler: dataCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"data",
				"Available Commands:",
				"query",
			},
		},
		{
			name:    "diagnose",
			handler: diagnoseCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"diagnose <seed>",
				"does not infer root cause",
			},
		},
		{
			name:    "metrics",
			handler: metricsCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"metrics",
				"Available Commands:",
				"series",
			},
		},
		{
			name:    "loki",
			handler: lokiCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"loki",
				"Available Commands:",
				"query",
				"instance-map",
			},
		},
		{
			name:    "events",
			handler: eventsCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"events",
				"Available Commands:",
				"list",
			},
		},
		{
			name:    "raw",
			handler: rawCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"raw",
				"Available Commands:",
				"request",
			},
		},
		{
			name:    "version",
			handler: versionCommandHandler,
			args:    []string{"--help"},
			want: []string{
				"Usage:",
				"version",
				"Show clinic CLI version information.",
			},
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			var stdout strings.Builder
			err := tc.handler(nil, tc.args, &stdout)
			if err != nil {
				t.Fatalf("%s command help error = %v", tc.name, err)
			}
			assertContainsAll(t, stdout.String(), tc.want)
		})
	}
}

func TestSubcommandHelpRendersForEverySubcommand(t *testing.T) {
	t.Parallel()

	testCases := []struct {
		name    string
		handler commandHandler
		args    []string
		want    []string
	}{
		{name: "auth set-key", handler: authCommandHandler, args: []string{"set-key", "--help"}, want: []string{"Usage:", "auth set-key", "Flags:", "--env string", "interactive"}},
		{name: "auth unset-key", handler: authCommandHandler, args: []string{"unset-key", "--help"}, want: []string{"Usage:", "auth unset-key", "Flags:", "--env string"}},
		{name: "auth set-url", handler: authCommandHandler, args: []string{"set-url", "--help"}, want: []string{"Usage:", "auth set-url", "Flags:", "--env string", "--url string"}},
		{name: "auth show", handler: authCommandHandler, args: []string{"show", "--help"}, want: []string{"Usage:", "auth show", "masked"}},
		{name: "env use", handler: envCommandHandler, args: []string{"use", "--help"}, want: []string{"Usage:", "env use <prod|staging|dev>", "Persist the active environment", "Examples:"}},
		{name: "env current", handler: envCommandHandler, args: []string{"current", "--help"}, want: []string{"Usage:", "env current", "Show the active environment", "Output:"}},
		{name: "env list", handler: envCommandHandler, args: []string{"list", "--help"}, want: []string{"Usage:", "env list", "List configured environments", "Output:"}},
		{name: "profile list", handler: profileCommandHandler, args: []string{"list", "--help"}, want: []string{"Usage:", "profile list", "env-local profile objects"}},
		{name: "profile current", handler: profileCommandHandler, args: []string{"current", "--help"}, want: []string{"Usage:", "profile current", "\"profile\": null"}},
		{name: "profile open", handler: profileCommandHandler, args: []string{"open", "--help"}, want: []string{"Usage:", "profile open [<name>]", "Open profile clinic_url in the default browser"}},
		{name: "profile use", handler: profileCommandHandler, args: []string{"use", "--help"}, want: []string{"Usage:", "profile use <name>", "selected profile object"}},
		{name: "profile set", handler: profileCommandHandler, args: []string{"set", "--help"}, want: []string{"Usage:", "profile set <name>", "Flags:", "--cluster-id string", "selected env", "fixed cluster metadata", "reserved name \"current\""}},
		{name: "profile delete", handler: profileCommandHandler, args: []string{"delete", "--help"}, want: []string{"Usage:", "profile delete <name>", "Deleting the active profile is allowed"}},
		{name: "cluster search", handler: clusterCommandHandler, args: []string{"search", "--help"}, want: []string{"Usage:", "cluster search", "Flags:", "--query string", "--deploy-type string", "Provide at least one of --query or --deploy-type", "Deleted clusters are excluded by default"}},
		{name: "cluster search-id", handler: clusterCommandHandler, args: []string{"search-id", "--help"}, want: []string{"Usage:", "cluster search-id", "Flags:", "--cluster-id string", "auto-creates one profile", "does not switch the active profile"}},
		{name: "cluster get", handler: clusterCommandHandler, args: []string{"get", "--help"}, want: []string{"Usage:", "cluster get", "Flags:", "--org-id string", "--cluster-id string"}},
		{name: "cluster get-by-id", handler: clusterCommandHandler, args: []string{"get-by-id", "--help"}, want: []string{"Usage:", "cluster get-by-id", "Flags:", "--cluster-id string", "dashboard/clusters"}},
		{name: "cluster topology", handler: clusterCommandHandler, args: []string{"topology", "--help"}, want: []string{"Usage:", "cluster topology", "Flags:", "--cluster-id string", "resource-pool/components", "premium resource pool"}},
		{name: "data query", handler: dataCommandHandler, args: []string{"query", "--help"}, want: []string{"Usage:", "data query", "Flags:", "--cluster-id string", "--sql string", "--timeout int"}},
		{name: "data schema", handler: dataCommandHandler, args: []string{"schema", "--help"}, want: []string{"Usage:", "data schema", "Flags:", "--cluster-id string", "--tables string", "comma-separated"}},
		{name: "metrics query", handler: metricsCommandHandler, args: []string{"query", "--help"}, want: []string{"Usage:", "metrics query --cluster-id <cluster-id> --query <promql>", "-p, --pool", "--time string"}},
		{name: "metrics range", handler: metricsCommandHandler, args: []string{"range", "--help"}, want: []string{"Usage:", "metrics range --cluster-id <cluster-id> --query <promql> --start <start> --end <end>", "-p, --pool", "--data-server", "--ds", "node_*", "/clinic/api/v1/data/metrics", "CLINIC_RANGE_START", "CLINIC_RANGE_END", "-o, --output string", "echarts, json, tui", "Default: echarts", "attempts to open it in a browser", "Use tui only when stdout is a terminal"}},
		{name: "metrics series", handler: metricsCommandHandler, args: []string{"series", "--help"}, want: []string{"Usage:", "metrics series --cluster-id <cluster-id> --match <selector>", "-p, --pool", "--match"}},
		{name: "loki query", handler: lokiCommandHandler, args: []string{"query", "--help"}, want: []string{"Usage:", "loki query [<logql>] --cluster-id <cluster-id> --start <time> --end <time>", "--allow-explicit-scope", "--skip-namespace-injection", "-o, --output string", "Default: 10", "Range: 1-1000", "now-<duration>", "optional timezone", "CLINIC_RANGE_START", "CLINIC_RANGE_END", "Profile scoping:", "Use {} for content-only searches"}},
		{name: "loki instance-map", handler: lokiCommandHandler, args: []string{"instance-map", "--help"}, want: []string{"Usage:", "loki instance-map --cluster-id <cluster-id> --start <time> --end <time>", "-o, --output string", "Default: 1000", "table, json", "Default: table"}},
		{name: "loki labels", handler: lokiCommandHandler, args: []string{"labels", "--help"}, want: []string{"Usage:", "loki labels --cluster-id <cluster-id>", "label names", "time bounds", "s/ms/ns"}},
		{name: "loki label-values", handler: lokiCommandHandler, args: []string{"label-values", "--help"}, want: []string{"Usage:", "loki label-values --cluster-id <cluster-id> --label <label>", "url.PathEscape", "range defaults", "defaults to local"}},
		{name: "events list", handler: eventsCommandHandler, args: []string{"list", "--help"}, want: []string{"Usage:", "events list", "now-<duration>", "defaults to local", "epoch in s/ms/ns", "Flags:", "--cluster-id string", "--start string", "--end string", "--cursor string"}},
		{name: "raw request", handler: rawCommandHandler, args: []string{"request", "--help"}, want: []string{"Usage:", "raw request", "Flags:", "--method string", "--path string", "--query stringArray", "--header stringArray", "@file"}},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			var stdout strings.Builder
			err := tc.handler(nil, tc.args, &stdout)
			if err != nil {
				t.Fatalf("%s help error = %v", tc.name, err)
			}
			assertContainsAll(t, stdout.String(), tc.want)
		})
	}
}

func TestMetricsGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := metricsCommandHandler(nil, []string{"range", "--help"}, &stdout); err != nil {
		t.Fatalf("metrics range help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Run a range PromQL query.",
		"Usage:",
		"metrics range --cluster-id <cluster-id> --query <promql> --start <start> --end <end>",
		"Flags:",
		"-p, --pool",
		"--data-server",
		"--ds",
		"-o, --output string",
		"echarts, json, tui",
		"Default: echarts",
		"Use tui only when stdout is a terminal",
		"Examples:",
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:"})
}

func TestLokiGeneratedHelp(t *testing.T) {
	t.Parallel()

	var stdout strings.Builder
	if err := lokiCommandHandler(nil, []string{"query", "--help"}, &stdout); err != nil {
		t.Fatalf("loki query help error = %v", err)
	}

	output := stdout.String()
	assertContainsAll(t, output, []string{
		"Run a Loki query_range request.",
		"Usage:",
		"loki query [<logql>] --cluster-id <cluster-id> --start <time> --end <time>",
		"Profile scoping:",
		"clinic automatically scopes Loki queries to the selected profile/cluster.",
		"Do not put cluster_env or namespace in the LogQL selector during normal use.",
		"clinic injects them automatically. Use {} for content-only searches.",
		"Omitted LogQL and {} remain supported for non-Starter/Essential tiers.",
		`Starter and Essential require exactly one selector with a non-empty equality cluster="..." matcher.`,
		"Starter and Essential queries route through the regional system-log datasource.",
		"Essential V2 and Premium routing remains unchanged.",
		"Explicit cluster_env or namespace selectors are only for intentional raw/cross-profile or cross-namespace investigations.",
		"Flags:",
		"--allow-explicit-scope",
		"--skip-namespace-injection",
		"-o, --output string",
		"Default: 10",
		"Range: 1-1000",
		"CLINIC_RANGE_START",
		"CLINIC_RANGE_END",
		"Examples:",
		`clinic loki query --start now-1h --end now '{} |= "Request range exceeds bound"'`,
		`clinic loki query --start now-1h --end now '{} |~ "split|bucket|region"'`,
		`clinic loki query --start now-1h --end now '{app="tidb"} |= "slow query"'`,
	})
	assertContainsNone(t, output, []string{"Required flags:", "Optional flags:", "{cluster_env=", `namespace=~".*"`})
}

func TestMetricsDataServerHelpScope(t *testing.T) {
	t.Parallel()

	testCases := []struct {
		name   string
		args   []string
		want   []string
		absent []string
	}{
		{
			name:   "metrics range documents data-server without temporal wording",
			args:   []string{"range", "--help"},
			want:   []string{"--data-server", "--ds", "node_*", "/clinic/api/v1/data/metrics"},
			absent: []string{"milestone"},
		},
		{
			name:   "metrics query does not mention data-server",
			args:   []string{"query", "--help"},
			absent: []string{"--data-server", "--ds", "/clinic/api/v1/data/metrics"},
		},
		{
			name:   "metrics series does not mention data-server",
			args:   []string{"series", "--help"},
			absent: []string{"--data-server", "--ds", "/clinic/api/v1/data/metrics"},
		},
	}

	for _, tc := range testCases {
		tc := tc
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			var stdout strings.Builder
			err := metricsCommandHandler(nil, tc.args, &stdout)
			if err != nil {
				t.Fatalf("%s help error = %v", tc.name, err)
			}

			assertContainsAll(t, stdout.String(), tc.want)
			assertContainsNone(t, stdout.String(), tc.absent)
		})
	}
}

func assertContainsAll(t *testing.T, got string, want []string) {
	t.Helper()
	for _, fragment := range want {
		if !strings.Contains(got, fragment) {
			t.Fatalf("help output missing %q\noutput:\n%s", fragment, got)
		}
	}
}

func assertContainsNone(t *testing.T, got string, want []string) {
	t.Helper()
	for _, fragment := range want {
		if strings.Contains(got, fragment) {
			t.Fatalf("help output unexpectedly contained %q\noutput:\n%s", fragment, got)
		}
	}
}
