package app

import (
	"context"
	"fmt"
	"strings"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	containerPkg "coopcloud.tech/abra/pkg/container"
	"coopcloud.tech/abra/pkg/i18n"
	"coopcloud.tech/abra/pkg/log"
	"coopcloud.tech/abra/pkg/upstream/container"
	"github.com/docker/cli/cli/command"
	containertypes "github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"
	"github.com/spf13/cobra"
)

// translators: `abra app run` aliases. use a comma separated list of aliases
// with no spaces in between
var appRunAliases = i18n.G("r")

var AppRunCommand = &cobra.Command{
	// translators: `app run` command
	Use:     i18n.G("run <domain> <service> <cmd> [[args] [flags] | [flags] -- [args]]"),
	Aliases: strings.Split(appRunAliases, ","),
	// translators: Short description for `app run` command
	Short: i18n.G("Run a command inside a service container"),
	Example: i18n.G(`  # run <cmd> with args/flags
  abra app run 1312.net app -- ls -lha

  # run <cmd> without args/flags
  abra app run 1312.net app bash --user nobody

  # run <cmd> with both kinds of args/flags 
  abra app run 1312.net app --user nobody -- ls -lha`),
	Args: cobra.MinimumNArgs(3),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		switch l := len(args); l {
		case 0:
			return autocomplete.AppNameComplete()
		case 1:
			return autocomplete.ServiceNameComplete(args[0])
		case 2:
			return autocomplete.CommandNameComplete(args[0])
		default:
			return nil, cobra.ShellCompDirectiveError
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		app := internal.ValidateApp(args)

		cl, err := client.New(app.Server)
		if err != nil {
			log.Fatal(err)
		}

		serviceName := args[1]
		stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), serviceName)

		filters := filters.NewArgs()
		filters.Add("name", stackAndServiceName)

		targetContainer, err := containerPkg.GetContainer(context.Background(), cl, filters, false)
		if err != nil {
			log.Fatal(err)
		}

		userCmd := args[2:]
		execCreateOpts := containertypes.ExecOptions{
			AttachStderr: true,
			AttachStdin:  true,
			AttachStdout: true,
			Cmd:          userCmd,
			Detach:       false,
			Tty:          true,
		}

		if runAsUser != "" {
			execCreateOpts.User = runAsUser
		}
		if noTTY {
			execCreateOpts.Tty = false
		}

		dcli, err := command.NewDockerCli()
		if err != nil {
			log.Fatal(err)
		}

		if _, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil {
			log.Fatal(err)
		}
	},
}

var (
	noTTY     bool
	runAsUser string
)

func init() {
	AppRunCommand.Flags().BoolVarP(&noTTY,
		i18n.G("no-tty"),
		i18n.G("t"),
		false,
		i18n.G("do not request a TTY"),
	)

	AppRunCommand.Flags().StringVarP(
		&runAsUser,
		i18n.G("user"),
		i18n.G("u"),
		"",
		i18n.G("run command as user"),
	)
}
