package flag

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/pkg/errors"
	"github.com/urfave/cli/v2"
	"gitlab.com/wpetit/goweb/cli/format"
	"gitlab.com/wpetit/goweb/cli/format/table"
)

func ComposeFlags(flags ...cli.Flag) []cli.Flag {
	baseFlags := []cli.Flag{
		&cli.StringFlag{
			Name:    "server",
			Aliases: []string{"s"},
			Usage:   "use `SERVER` as server url",
			Value:   "http://127.0.0.1:8081",
		},
		&cli.StringFlag{
			Name:    "format",
			Aliases: []string{"f"},
			Usage:   fmt.Sprintf("use `FORMAT` as output format (available: %s)", format.Available()),
			Value:   string(table.Format),
		},
		&cli.StringFlag{
			Name:    "output-mode",
			Aliases: []string{"m"},
			Usage:   fmt.Sprintf("use `MODE` as output mode (available: %s)", []format.OutputMode{format.OutputModeCompact, format.OutputModeWide}),
			Value:   string(format.OutputModeCompact),
		},
		&cli.StringFlag{
			Name:    "token",
			Aliases: []string{"t"},
			EnvVars: []string{`BOUNCER_TOKEN`},
			Usage:   "use `TOKEN` as authentication token",
		},
		&cli.StringFlag{
			Name:      "token-file",
			EnvVars:   []string{`BOUNCER_TOKEN_FILE`},
			Usage:     "use `TOKEN_FILE` as file containing the authentication token",
			Value:     ".bouncer-token",
			TakesFile: true,
		},
	}

	flags = append(flags, baseFlags...)

	return flags
}

type BaseFlags struct {
	ServerURL  string
	Format     format.Format
	OutputMode format.OutputMode
	Token      string
	TokenFile  string
}

func GetBaseFlags(ctx *cli.Context) *BaseFlags {
	serverURL := ctx.String("server")
	rawFormat := ctx.String("format")
	rawOutputMode := ctx.String("output-mode")
	tokenFile := ctx.String("token-file")
	token := ctx.String("token")

	return &BaseFlags{
		ServerURL:  serverURL,
		Format:     format.Format(rawFormat),
		OutputMode: format.OutputMode(rawOutputMode),
		Token:      token,
		TokenFile:  tokenFile,
	}
}

func GetToken(flags *BaseFlags) (string, error) {
	if flags.Token != "" {
		return flags.Token, nil
	}

	if flags.TokenFile == "" {
		return "", nil
	}

	rawToken, err := ioutil.ReadFile(flags.TokenFile)
	if err != nil && !errors.Is(err, os.ErrNotExist) {
		return "", errors.WithStack(err)
	}

	if rawToken == nil {
		return "", nil
	}

	return strings.TrimSpace(string(rawToken)), nil
}