package app

import (
	"fmt"
	"sort"
	"strings"

	abraFormatter "coopcloud.tech/abra/cli/formatter"
	"coopcloud.tech/abra/cli/internal"
	appPkg "coopcloud.tech/abra/pkg/app"
	"coopcloud.tech/abra/pkg/client/stack"
	"coopcloud.tech/abra/pkg/config"
	"github.com/docker/distribution/reference"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v2"
)

// getImagePath returns the image name
func getImagePath(image string) (string, error) {
	img, err := reference.ParseNormalizedNamed(image)
	if err != nil {
		return "", err
	}
	path := reference.Path(img)
	if strings.Contains(path, "library") {
		path = strings.Split(path, "/")[1]
	}
	logrus.Debugf("parsed '%s' from '%s'", path, image)
	return path, nil
}

var appVersionCommand = &cli.Command{
	Name:    "version",
	Aliases: []string{"v"},
	Usage:   "Show version of all services in app",
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		composeFiles, err := config.GetAppComposeFiles(app.Type, app.Env)
		if err != nil {
			logrus.Fatal(err)
		}
		opts := stack.Deploy{Composefiles: composeFiles}
		compose, err := config.GetAppComposeConfig(app.Type, opts, app.Env)
		if err != nil {
			logrus.Fatal(err)
		}

		ch := make(chan stack.StackStatus, len(compose.Services))
		for _, service := range compose.Services {
			label := fmt.Sprintf("coop-cloud.%s.%s.version", app.StackName(), service.Name)
			go func(s string, l string) {
				ch <- stack.GetDeployedServicesByLabel(s, l)
			}(app.Server, label)
		}

		tableCol := []string{"name", "image", "version", "digest"}
		table := abraFormatter.CreateTable(tableCol)

		statuses := make(map[string]stack.StackStatus)
		for range compose.Services {
			status := <-ch
			if len(status.Services) > 0 {
				serviceName := appPkg.ParseServiceName(status.Services[0].Spec.Name)
				statuses[serviceName] = status
			}
		}

		sort.SliceStable(compose.Services, func(i, j int) bool {
			return compose.Services[i].Name < compose.Services[j].Name
		})

		for _, service := range compose.Services {
			if status, ok := statuses[service.Name]; ok {
				statusService := status.Services[0]
				label := fmt.Sprintf("coop-cloud.%s.%s.version", app.StackName(), service.Name)
				version, digest := appPkg.ParseVersionLabel(statusService.Spec.Labels[label])
				image, err := getImagePath(statusService.Spec.Labels["com.docker.stack.image"])
				if err != nil {
					logrus.Fatal(err)
				}
				table.Append([]string{service.Name, image, version, digest})
				continue
			}

			image, err := getImagePath(service.Image)
			if err != nil {
				logrus.Fatal(err)
			}
			table.Append([]string{service.Name, image, "?", "?"})
		}

		table.Render()
		return nil
	},
	BashComplete: func(c *cli.Context) {
		appNames, err := config.GetAppNames()
		if err != nil {
			logrus.Warn(err)
		}
		if c.NArg() > 0 {
			return
		}
		for _, a := range appNames {
			fmt.Println(a)
		}
	},
}