package server

import (
	"fmt"
	"strings"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/config"
	contextPkg "coopcloud.tech/abra/pkg/context"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/log"
	"github.com/docker/cli/cli/connhelper/ssh"
	"github.com/spf13/cobra"
)

var ServerListCommand = &cobra.Command{
	Use:     "list [flags]",
	Aliases: []string{"ls"},
	Short:   "List managed servers",
	Args:    cobra.NoArgs,
	Run: func(cmd *cobra.Command, args []string) {
		dockerContextStore := contextPkg.NewDefaultDockerContextStore()
		contexts, err := dockerContextStore.Store.List()
		if err != nil {
			log.Fatal(err)
		}

		table, err := formatter.CreateTable()
		if err != nil {
			log.Fatal(err)
		}

		headers := []string{"NAME", "HOST"}
		table.Headers(headers...)

		serverNames, err := config.ReadServerNames()
		if err != nil {
			log.Fatal(err)
		}

		var rows [][]string
		for _, serverName := range serverNames {
			var row []string
			for _, dockerCtx := range contexts {
				endpoint, err := contextPkg.GetContextEndpoint(dockerCtx)
				if err != nil && strings.Contains(err.Error(), "does not exist") {
					// No local context found, we can continue safely
					continue
				}

				if dockerCtx.Name == serverName {
					sp, err := ssh.ParseURL(endpoint)
					if err != nil {
						log.Fatal(err)
					}

					if sp.Host == "" {
						sp.Host = "unknown"
					}

					row = []string{serverName, sp.Host}
					rows = append(rows, row)
				}
			}

			if len(row) == 0 {
				if serverName == "default" {
					row = []string{serverName, "local"}
				} else {
					row = []string{serverName, "unknown"}
				}
				rows = append(rows, row)
			}

			table.Row(row...)
		}

		if internal.MachineReadable {
			out, err := formatter.ToJSON(headers, rows)
			if err != nil {
				log.Fatal("unable to render to JSON: %s", err)
			}

			fmt.Println(out)

			return
		}

		if err := formatter.PrintTable(table); err != nil {
			log.Fatal(err)
		}
	},
}

func init() {
	ServerListCommand.Flags().BoolVarP(
		&internal.MachineReadable,
		"machine",
		"m",
		false,
		"print machine-readable output",
	)
}
