package app

import (
	"strings"
	"time"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/config"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/service"
	stack "coopcloud.tech/abra/pkg/upstream/stack"
	"github.com/buger/goterm"
	dockerFormatter "github.com/docker/cli/cli/command/formatter"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	dockerClient "github.com/docker/docker/client"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v2"
)

var appPsCommand = &cli.Command{
	Name:        "ps",
	Usage:       "Check app status",
	Description: "This command shows a more detailed status output of a specific deployed app.",
	Aliases:     []string{"p"},
	Flags: []cli.Flag{
		internal.WatchFlag,
	},
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

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

		isDeployed, _, err := stack.IsDeployed(c.Context, cl, app.StackName())
		if err != nil {
			logrus.Fatal(err)
		}

		if !isDeployed {
			logrus.Fatalf("%s is not deployed?", app.Name)
		}

		if !internal.Watch {
			showPSOutput(c, app, cl)
			return nil
		}

		goterm.Clear()
		for {
			goterm.MoveCursor(1, 1)
			showPSOutput(c, app, cl)
			goterm.Flush()
			time.Sleep(2 * time.Second)
		}
	},
}

// showPSOutput renders ps output.
func showPSOutput(c *cli.Context, app config.App, cl *dockerClient.Client) {
	filters := filters.NewArgs()
	filters.Add("name", app.StackName())

	containers, err := cl.ContainerList(c.Context, types.ContainerListOptions{Filters: filters})
	if err != nil {
		logrus.Fatal(err)
	}

	tableCol := []string{"service name", "image", "created", "status", "state", "ports"}
	table := formatter.CreateTable(tableCol)

	for _, container := range containers {
		var containerNames []string
		for _, containerName := range container.Names {
			trimmed := strings.TrimPrefix(containerName, "/")
			containerNames = append(containerNames, trimmed)
		}

		tableRow := []string{
			service.ContainerToServiceName(container.Names, app.StackName()),
			formatter.RemoveSha(container.Image),
			formatter.HumanDuration(container.Created),
			container.Status,
			container.State,
			dockerFormatter.DisplayablePorts(container.Ports),
		}
		table.Append(tableRow)
	}

	table.Render()
}