// DescribeApplication describes an Application to provide usage information.
func DescribeApplication(app *Application) string {
	var help string

	if app.Logo != "" {
		help += fmt.Sprintf("%s\n", app.Logo)
	}

	help += fmt.Sprintf("%s version %s\n\n", app.Name, app.Version)
	help += fmt.Sprintf("%s\n", describeApplicationUsage(app))

	options := findApplicationOptions(app)

	if len(options) > 0 {
		help += fmt.Sprintf("\n%s", parameters.DescribeOptions(options))
	}

	if len(app.Commands) > 0 {
		help += fmt.Sprintf("\n%s", DescribeCommands(app.Commands))
		help += fmt.Sprintf(
			"\n  Run `$ %s COMMAND --help` for more information about a command.\n",
			app.UsageName,
		)
	}

	if len(app.Help) > 0 {
		help += "\nHELP:\n"
		help += wordwrap.Indent(app.Help, "  ", true) + "\n"
	}

	return help
}
// DescribeCommand describes a Command on an Application to provide usage information.
func DescribeCommand(app *Application, cmd *Command) string {
	var help string

	arguments := findCommandArguments(cmd)
	options := findCommandOptions(app, cmd)

	help += fmt.Sprintf("%s\n", describeCommandUsage(app, cmd, arguments, options))

	if len(arguments) > 0 {
		help += fmt.Sprintf("\n%s", parameters.DescribeArguments(arguments))
	}

	if len(options) > 0 {
		help += fmt.Sprintf("\n%s", parameters.DescribeOptions(options))
	}

	if len(cmd.Help) > 0 {
		help += "\nHELP:\n"
		help += wordwrap.Indent(cmd.Help, "  ", true) + "\n"
	}

	return help
}
func TestDescribeOptions(t *testing.T) {
	t.Run("should include a title", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{})

		assert.True(t, strings.Contains(result, "OPTIONS:"), "Expected a title.")
	})

	t.Run("should include option names", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names: []string{
					"t",
					"test",
				},
			},
		})

		assert.True(t, strings.Contains(result, "-t"), "Expected option name in result.")
		assert.True(t, strings.Contains(result, "--test"), "Expected option name in result.")
	})

	t.Run("should handle multiple arguments", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names: []string{
					"f",
					"foo",
				},
			},
			{
				Names: []string{
					"b",
					"bar",
				},
			},
		})

		assert.True(t, strings.Contains(result, "-f"), "Expected option name in result.")
		assert.True(t, strings.Contains(result, "--foo"), "Expected option name in result.")
		assert.True(t, strings.Contains(result, "-b"), "Expected option name in result.")
		assert.True(t, strings.Contains(result, "--bar"), "Expected option name in result.")
	})

	t.Run("should sort arguments into alphabetical order", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names: []string{
					"f",
					"foo",
				},
			},
			{
				Names: []string{
					"b",
					"bar",
				},
			},
		})

		fooIdx := strings.Index(result, "--foo")
		barIdx := strings.Index(result, "--bar")

		assert.True(t, fooIdx > barIdx, "Expected FOO to come after BAR.")
	})

	t.Run("should show value names", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names:     []string{"foo"},
				ValueMode: parameters.OptionValueRequired,
				ValueName: "FOO_NAME",
			},
		})

		assert.True(t, strings.Contains(result, "FOO_NAME"), "Expected value name in output.")
	})

	t.Run("should show value names as optional if they are", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names:     []string{"foo"},
				ValueMode: parameters.OptionValueOptional,
				ValueName: "FOO_NAME",
			},
		})

		assert.True(t, strings.Contains(result, "[=FOO_NAME]"), "Expected value name in output.")
	})

	t.Run("should sort short options before long options names", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names: []string{
					"foo",
					"f",
				},
			},
		})

		fooIdx := strings.Index(result, "--foo")
		fIdx := strings.Index(result, "-f")

		assert.True(t, fooIdx > fIdx, "Expected --foo to come after -f.")
	})

	t.Run("should sort short options into alphabetical order", func(t *testing.T) {
		result := parameters.DescribeOptions([]parameters.Option{
			{
				Names: []string{
					"f",
					"b",
				},
			},
		})

		bIdx := strings.Index(result, "-b")
		fIdx := strings.Index(result, "-f")

		assert.True(t, fIdx > bIdx, "Expected -f to come after -b.")
	})
}