package main

import (
	"context"
	"errors"
	"fmt"
	"os"
	"regexp"
	"strings"

	"github.com/rancher/cli/cmd"
	"github.com/rancher/cli/config"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v3"
)

var VERSION = "dev"

var AppHelpTemplate = `{{.Usage}}

Usage: {{.Name}} {{if .Flags}}[OPTIONS] {{end}}COMMAND [arg...]

Version: {{.Version}}
{{if .VisibleFlags}}
Options:
  {{range .VisibleFlags}}{{.}}
  {{end}}{{end}}
Commands:
  {{range .VisibleCommands}}{{.Name}}{{with .Aliases}}, {{join . ", "}}{{end}}{{ "\t" }}{{.Usage}}
  {{end}}
Run '{{.Name}} COMMAND --help' for more information on a command.
`

var CommandHelpTemplate = `{{.Usage}}
{{if .Description}}{{.Description}}{{end}}
Usage: 
	{{.FullName}} {{if .Flags}}[OPTIONS] {{end}}{{if ne "None" .ArgsUsage}}{{if ne "" .ArgsUsage}}{{.ArgsUsage}}{{else}}[arg...]{{end}}{{end}}

{{if .VisibleFlags}}Options:{{range .VisibleFlags}}
	 {{.}}{{end}}{{end}}
`

var SubcommandHelpTemplate = `{{.Usage}}
{{if .Description}}{{.Description}}{{end}}
Usage:
   {{.FullName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}

Commands:{{range .VisibleCategories}}{{if .Name}}
   {{.Name}}:{{end}}{{range .VisibleCommands}}
     {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
{{end}}{{if .VisibleFlags}}
Options:
   {{range .VisibleFlags}}{{.}}
   {{end}}{{end}}
`

func main() {
	if err := mainErr(); err != nil {
		logrus.Fatal(err)
	}
}

func mainErr() error {
	cli.CommandHelpTemplate = CommandHelpTemplate
	cli.SubcommandHelpTemplate = SubcommandHelpTemplate

	configDir, err := cmd.ConfigDir()
	if err != nil {
		return err
	}

	rootCmd := &cli.Command{
		Name:                          "rancher",
		Usage:                         "Rancher CLI, managing containers one UTF-8 character at a time",
		Version:                       VERSION,
		CustomRootCommandHelpTemplate: AppHelpTemplate,
		EnableShellCompletion:         true,
		ConfigureShellCompletionCommand: func(cmd *cli.Command) {
			cmd.Hidden = false
		},
		Before: func(ctx context.Context, c *cli.Command) (context.Context, error) {
			if c.Bool("debug") {
				logrus.SetLevel(logrus.DebugLevel)
			}

			path := cmd.GetConfigPath(c)
			warnings, err := config.GetFilePermissionWarnings(path)
			if err != nil {
				// We don't want to block the execution of the CLI in that case
				logrus.Errorf("Unable to verify config file permission: %s. Continuing.", err)
			}
			for _, warning := range warnings {
				logrus.Warning(warning)
			}

			return ctx, nil
		},
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:  "debug",
				Usage: "Debug logging",
			},
			&cli.StringFlag{
				Name:    "config",
				Aliases: []string{"c"},
				Usage:   "Path to rancher config",
				Sources: cli.EnvVars("RANCHER_CONFIG_DIR"),
				Value:   configDir,
			},
		},
		Commands: []*cli.Command{
			cmd.ClusterCommand(),
			cmd.ContextCommand(),
			cmd.InspectCommand(),
			cmd.KubectlCommand(),
			cmd.LoginCommand(),
			cmd.MachineCommand(),
			cmd.NamespaceCommand(),
			cmd.NodeCommand(),
			cmd.ProjectCommand(),
			cmd.PsCommand(),
			cmd.ServerCommand(),
			cmd.SettingsCommand(),
			cmd.SSHCommand(),
			cmd.UpCommand(),
			cmd.WaitCommand(),
			cmd.CredentialCommand(),
		},
	}

	parsed, err := parseArgs(os.Args)
	if err != nil {
		logrus.Error(err)
		os.Exit(1)
	}

	return rootCmd.Run(context.Background(), parsed)
}

var singleAlphaLetterRegexp = regexp.MustCompile("[a-zA-Z]")

func parseArgs(args []string) ([]string, error) {
	result := []string{}
	for _, arg := range args {
		if strings.HasPrefix(arg, "-") && !strings.HasPrefix(arg, "--") && len(arg) > 1 {
			for i, c := range arg[1:] {
				if string(c) == "=" {
					if i < 1 {
						return nil, errors.New("invalid input with '-' and '=' flag")
					}
					result[len(result)-1] = result[len(result)-1] + arg[i+1:]
					break
				} else if singleAlphaLetterRegexp.MatchString(string(c)) {
					result = append(result, "-"+string(c))
				} else {
					return nil, fmt.Errorf("invalid input %s in flag", string(c))
				}
			}
		} else {
			result = append(result, arg)
		}
	}
	return result, nil
}
