package cmd

import (
	"fmt"
	"io"

	"github.com/spf13/cobra"

	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"

	osclient "github.com/openshift/origin/pkg/client"
	"github.com/openshift/origin/pkg/cmd/templates"
	"github.com/openshift/origin/pkg/cmd/util/clientcmd"
	userapi "github.com/openshift/origin/pkg/user/api"
)

const WhoAmIRecommendedCommandName = "whoami"

var whoamiLong = templates.LongDesc(`
	Show information about the current session

	The default options for this command will return the currently authenticated user name
	or an empty string.  Other flags support returning the currently used token or the
	user context.`)

type WhoAmIOptions struct {
	UserInterface osclient.UserInterface

	Out io.Writer
}

func NewCmdWhoAmI(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
	o := &WhoAmIOptions{}

	cmd := &cobra.Command{
		Use:   name,
		Short: "Return information about the current session",
		Long:  whoamiLong,
		Run: func(cmd *cobra.Command, args []string) {
			err := RunWhoAmI(f, out, cmd, args, o)
			kcmdutil.CheckErr(err)
		},
	}

	// Deprecated in 1.4
	// Remove in 1.5 so we can use --token and --context for building the client again
	cmd.Flags().Bool("token", false, "Deprecated, use --show-token instead")
	cmd.Flags().Bool("context", false, "Deprecated, use --show-context instead")
	cmd.Flags().MarkDeprecated("token", "use -t or --show-token instead")
	cmd.Flags().MarkDeprecated("context", "use -c or --show-context instead")
	cmd.Flags().MarkHidden("token")
	cmd.Flags().MarkHidden("context")

	cmd.Flags().BoolP("show-token", "t", false, "Print the token the current session is using. This will return an error if you are using a different form of authentication.")
	cmd.Flags().BoolP("show-context", "c", false, "Print the current user context name")
	cmd.Flags().Bool("show-server", false, "Print the current server's REST API URL")

	return cmd
}

func (o WhoAmIOptions) WhoAmI() (*userapi.User, error) {
	me, err := o.UserInterface.Get("~")
	if err == nil {
		fmt.Fprintf(o.Out, "%s\n", me.Name)
	}

	return me, err
}

func RunWhoAmI(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, o *WhoAmIOptions) error {
	if kcmdutil.GetFlagBool(cmd, "token") || kcmdutil.GetFlagBool(cmd, "show-token") {
		cfg, err := f.OpenShiftClientConfig.ClientConfig()
		if err != nil {
			return err
		}
		if len(cfg.BearerToken) == 0 {
			return fmt.Errorf("no token is currently in use for this session")
		}
		fmt.Fprintf(out, "%s\n", cfg.BearerToken)
		return nil
	}
	if kcmdutil.GetFlagBool(cmd, "context") || kcmdutil.GetFlagBool(cmd, "show-context") {
		cfg, err := f.OpenShiftClientConfig.RawConfig()
		if err != nil {
			return err
		}
		if len(cfg.CurrentContext) == 0 {
			return fmt.Errorf("no context has been set")
		}
		fmt.Fprintf(out, "%s\n", cfg.CurrentContext)
		return nil
	}
	if kcmdutil.GetFlagBool(cmd, "show-server") {
		cfg, err := f.OpenShiftClientConfig.RawConfig()
		if err != nil {
			return err
		}
		for _, c := range cfg.Clusters {
			fmt.Fprintf(out, "%s\n", c.Server)
			return nil
		}
		return fmt.Errorf("unable to get clusters. Cannot retrieve server URL.")
	}

	client, _, err := f.Clients()
	if err != nil {
		return err
	}

	o.UserInterface = client.Users()
	o.Out = out

	_, err = o.WhoAmI()
	return err
}