package app

import (
	"context"
	"errors"
	"fmt"

	"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/log"
	"coopcloud.tech/abra/pkg/upstream/container"
	"github.com/docker/cli/cli/command"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/urfave/cli"
)

var user string
var userFlag = &cli.StringFlag{
	Name:        "user, u",
	Value:       "",
	Destination: &user,
}

var noTTY bool
var noTTYFlag = &cli.BoolFlag{
	Name:        "no-tty, t",
	Destination: &noTTY,
}

var appRunCommand = cli.Command{
	Name:    "run",
	Aliases: []string{"r"},
	Flags: []cli.Flag{
		internal.DebugFlag,
		noTTYFlag,
		userFlag,
	},
	Before:       internal.SubCommandBefore,
	ArgsUsage:    "<domain> <service> <args>...",
	Usage:        "Run a command in a service container",
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if len(c.Args()) < 2 {
			internal.ShowSubcommandHelpAndError(c, errors.New("no <service> provided?"))
		}

		if len(c.Args()) < 3 {
			internal.ShowSubcommandHelpAndError(c, errors.New("no <args> provided?"))
		}

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

		serviceName := c.Args().Get(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)
		}

		cmd := c.Args()[2:]
		execCreateOpts := types.ExecConfig{
			AttachStderr: true,
			AttachStdin:  true,
			AttachStdout: true,
			Cmd:          cmd,
			Detach:       false,
			Tty:          true,
		}

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

		// FIXME: avoid instantiating a new CLI
		dcli, err := command.NewDockerCli()
		if err != nil {
			log.Fatal(err)
		}

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

		return nil
	},
}
