package command

import (
	"fmt"
	"path/filepath"
	"strings"

	svchost "github.com/hashicorp/terraform-svchost"
	"github.com/hashicorp/terraform/internal/command/cliconfig"
	"github.com/hashicorp/terraform/internal/tfdiags"
)

// LogoutCommand is a Command implementation which removes stored credentials
// for a remote service host.
type LogoutCommand struct {
	Meta
}

// Run implements cli.Command.
func (c *LogoutCommand) Run(args []string) int {
	args = c.Meta.process(args)
	cmdFlags := c.Meta.defaultFlagSet("logout")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error(
			"The logout command expects at most one argument: the host to log out of.")
		cmdFlags.Usage()
		return 1
	}

	var diags tfdiags.Diagnostics

	givenHostname := "app.terraform.io"
	if len(args) != 0 {
		givenHostname = args[0]
	}

	hostname, err := svchost.ForComparison(givenHostname)
	if err != nil {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Invalid hostname",
			fmt.Sprintf("The given hostname %q is not valid: %s.", givenHostname, err.Error()),
		))
		c.showDiagnostics(diags)
		return 1
	}

	// From now on, since we've validated the given hostname, we should use
	// dispHostname in the UI to ensure we're presenting it in the canonical
	// form, in case that helps users with debugging when things aren't
	// working as expected. (Perhaps the normalization is part of the cause.)
	dispHostname := hostname.ForDisplay()

	creds := c.Services.CredentialsSource().(*cliconfig.CredentialsSource)
	filename, _ := creds.CredentialsFilePath()
	credsCtx := &loginCredentialsContext{
		Location:      creds.HostCredentialsLocation(hostname),
		LocalFilename: filename, // empty in the very unlikely event that we can't select a config directory for this user
		HelperType:    creds.CredentialsHelperType(),
	}

	if credsCtx.Location == cliconfig.CredentialsInOtherFile {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			fmt.Sprintf("Credentials for %s are manually configured", dispHostname),
			"The \"terraform logout\" command cannot log out because credentials for this host are manually configured in a CLI configuration file.\n\nTo log out, revoke the existing credentials and remove that block from the CLI configuration.",
		))
	}

	if diags.HasErrors() {
		c.showDiagnostics(diags)
		return 1
	}

	switch credsCtx.Location {
	case cliconfig.CredentialsNotAvailable:
		c.Ui.Output(fmt.Sprintf("No credentials for %s are stored.\n", dispHostname))
		return 0
	case cliconfig.CredentialsViaHelper:
		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the configured\n%q credentials helper.\n", dispHostname, credsCtx.HelperType))
	case cliconfig.CredentialsInPrimaryFile:
		c.Ui.Output(fmt.Sprintf("Removing the stored credentials for %s from the following file:\n    %s\n", dispHostname, credsCtx.LocalFilename))
	}

	err = creds.ForgetForHost(hostname)
	if err != nil {
		diags = diags.Append(tfdiags.Sourceless(
			tfdiags.Error,
			"Failed to remove API token",
			fmt.Sprintf("Unable to remove stored API token: %s", err),
		))
	}

	c.showDiagnostics(diags)
	if diags.HasErrors() {
		return 1
	}

	c.Ui.Output(
		fmt.Sprintf(
			c.Colorize().Color(strings.TrimSpace(`
[green][bold]Success![reset] [bold]Terraform has removed the stored API token for %s.[reset]
`)),
			dispHostname,
		) + "\n",
	)

	return 0
}

// Help implements cli.Command.
func (c *LogoutCommand) Help() string {
	defaultFile := c.defaultOutputFile()
	if defaultFile == "" {
		// Because this is just for the help message and it's very unlikely
		// that a user wouldn't have a functioning home directory anyway,
		// we'll just use a placeholder here. The real command has some
		// more complex behavior for this case. This result is not correct
		// on all platforms, but given how unlikely we are to hit this case
		// that seems okay.
		defaultFile = "~/.terraform/credentials.tfrc.json"
	}

	helpText := `
Usage: terraform [global options] logout [hostname]

  Removes locally-stored credentials for specified hostname.

  Note: the API token is only removed from local storage, not destroyed on the
  remote server, so it will remain valid until manually revoked.

  If no hostname is provided, the default hostname is app.terraform.io.
      %s
`
	return strings.TrimSpace(helpText)
}

// Synopsis implements cli.Command.
func (c *LogoutCommand) Synopsis() string {
	return "Remove locally-stored credentials for a remote host"
}

func (c *LogoutCommand) defaultOutputFile() string {
	if c.CLIConfigDir == "" {
		return "" // no default available
	}
	return filepath.Join(c.CLIConfigDir, "credentials.tfrc.json")
}
