package commands

import (
	"fmt"

	"github.com/manifoldco/promptui"
	"github.com/urfave/cli/v2"

	"github.com/photoprism/photoprism/internal/config"
	"github.com/photoprism/photoprism/internal/entity"
	"github.com/photoprism/photoprism/pkg/authn"
	"github.com/photoprism/photoprism/pkg/clean"
	"github.com/photoprism/photoprism/pkg/rnd"
	"github.com/photoprism/photoprism/pkg/time/unix"
	"github.com/photoprism/photoprism/pkg/txt/report"
)

// AuthAddFlags specifies the "photoprism auth add" command flags.
var AuthAddFlags = []cli.Flag{
	&cli.StringFlag{
		Name:    "name",
		Aliases: []string{"n"},
		Usage:   "`CLIENT` name to help identify the application",
	},
	ScopeFlag("token authorization `SCOPE` as space-separated resources, or '*' for full access"),
	&cli.Int64Flag{
		Name:    "expires",
		Aliases: []string{"e"},
		Usage:   "token `LIFETIME` in seconds, or -1 to disable the limit",
		Value:   unix.Year,
	},
}

// AuthAddCommand configures the command name, flags, and action.
var AuthAddCommand = &cli.Command{
	Name:  "add",
	Usage: "Adds a new authentication secret for client applications",
	Description: "If you specify a username as argument, an app password will be created for this user account." +
		" It can be used as a password replacement to grant limited access to client applications.",
	ArgsUsage: "[username]",
	Flags:     AuthAddFlags,
	Action:    authAddAction,
}

// authAddAction shows detailed session information.
func authAddAction(ctx *cli.Context) error {
	return CallWithDependencies(ctx, func(conf *config.Config) error {
		// Get username from command flag.
		userName := clean.Username(ctx.Args().First())

		// Find user account.
		user := entity.FindUserByName(userName)

		if user == nil && userName != "" {
			return fmt.Errorf("user %s not found", clean.LogQuote(userName))
		}

		// Get client name from command flag or ask for it.
		clientName := ctx.String("name")

		if clientName == "" {
			prompt := promptui.Prompt{
				Label:   "Client Name",
				Default: rnd.Name(),
			}

			res, err := prompt.Run()

			if err != nil {
				return err
			}

			clientName = clean.Name(res)
		}

		// Get auth scope from command flag or ask for it.
		authScope := ctx.String("scope")

		if authScope == "" {
			prompt := promptui.Prompt{
				Label:   "Authorization Scope",
				Default: "*",
			}

			res, err := prompt.Run()

			if err != nil {
				return err
			}

			authScope = clean.Scope(res)
		}

		// Create session and show the authentication secret.
		sess, err := entity.AddClientSession(clientName, ctx.Int64("expires"), authScope, authn.GrantCLI, user)

		if err != nil {
			return fmt.Errorf("failed to create authentication secret: %s", err)
		} else {
			// Show client authentication credentials.
			if sess.UserUID == "" {
				fmt.Printf("\nPLEASE COPY THE FOLLOWING RANDOMLY GENERATED ACCESS TOKEN AND KEEP IT IN A SAFE PLACE, AS YOU WILL NOT BE ABLE TO SEE IT AGAIN:\n")
				fmt.Printf("\n%s\n", report.Credentials("Access Token", sess.AuthToken(), "Authorization Scope", sess.Scope()))
			} else {
				fmt.Printf("\nPLEASE COPY THE FOLLOWING RANDOMLY GENERATED APP PASSWORD AND KEEP IT IN A SAFE PLACE, AS YOU WILL NOT BE ABLE TO SEE IT AGAIN:\n")
				fmt.Printf("\n%s\n", report.Credentials("App Password", sess.AuthToken(), "Authorization Scope", sess.Scope()))
			}

		}

		return err
	})
}
