package app

import (
	"fmt"
	"os"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/config"
	"github.com/AlecAivazis/survey/v2"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli/v2"
)

// Volumes stores the variable from VolumesFlag
var Volumes bool

// VolumesFlag is used to specify if volumes should be deleted when deleting an app
var VolumesFlag = &cli.BoolFlag{
	Name:        "volumes",
	Value:       false,
	Destination: &Volumes,
}

var appRemoveCommand = &cli.Command{
	Name:    "remove",
	Usage:   "Remove an already undeployed app",
	Aliases: []string{"rm"},
	Flags: []cli.Flag{
		VolumesFlag,
		internal.ForceFlag,
	},
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if !internal.Force {
			response := false
			prompt := &survey.Confirm{
				Message: fmt.Sprintf("about to delete %s, are you sure?", app.Name),
			}
			if err := survey.AskOne(prompt, &response); err != nil {
				logrus.Fatal(err)
			}
			if !response {
				logrus.Fatal("user aborted app removal")
			}
		}

		appFiles, err := config.LoadAppFiles("")
		if err != nil {
			logrus.Fatal(err)
		}

		cl, err := client.New(app.Server)
		if err != nil {
			logrus.Fatal(err)
		}
		if !internal.Force {
			// FIXME: only query for app we are interested in, not all of them!
			statuses, err := config.GetAppStatuses(appFiles)
			if err != nil {
				logrus.Fatal(err)
			}
			if statuses[app.Name] == "deployed" {
				logrus.Fatalf("'%s' is still deployed. Run \"abra app %s undeploy\" or pass --force", app.Name, app.Name)
			}
		}

		fs := filters.NewArgs()
		fs.Add("name", app.Name)
		secretList, err := cl.SecretList(c.Context, types.SecretListOptions{Filters: fs})
		if err != nil {
			logrus.Fatal(err)
		}

		secrets := make(map[string]string)
		var secretNames []string

		for _, cont := range secretList {
			secrets[cont.Spec.Annotations.Name] = cont.ID // we have to map the names to ID's
			secretNames = append(secretNames, cont.Spec.Annotations.Name)
		}

		if len(secrets) > 0 {
			var secretNamesToRemove []string
			if !internal.Force {
				secretsPrompt := &survey.MultiSelect{
					Message: "which secrets do you want to remove?",
					Options: secretNames,
					Default: secretNames,
				}
				if err := survey.AskOne(secretsPrompt, &secretNamesToRemove); err != nil {
					logrus.Fatal(err)
				}
			}

			for _, name := range secretNamesToRemove {
				err := cl.SecretRemove(c.Context, secrets[name])
				if err != nil {
					logrus.Fatal(err)
				}
				logrus.Info(fmt.Sprintf("secret: %s removed", name))
			}
		} else {
			logrus.Info("no secrets to remove")
		}

		volumeListOKBody, err := cl.VolumeList(c.Context, fs)
		volumeList := volumeListOKBody.Volumes
		if err != nil {
			logrus.Fatal(err)
		}

		var vols []string
		for _, vol := range volumeList {
			vols = append(vols, vol.Name)
		}

		if len(vols) > 0 {
			if Volumes {
				var removeVols []string
				if !internal.Force {
					volumesPrompt := &survey.MultiSelect{
						Message: "which volumes do you want to remove?",
						Options: vols,
						Default: vols,
					}
					if err := survey.AskOne(volumesPrompt, &removeVols); err != nil {
						logrus.Fatal(err)
					}
				}
				for _, vol := range removeVols {
					err := cl.VolumeRemove(c.Context, vol, internal.Force) // last argument is for force removing
					if err != nil {
						logrus.Fatal(err)
					}
					logrus.Info(fmt.Sprintf("volume %s removed", vol))
				}
			} else {
				logrus.Info("no volumes were removed")
			}
		} else {
			logrus.Info("no volumes to remove")
		}

		err = os.Remove(app.Path)
		if err != nil {
			logrus.Fatal(err)
		}
		logrus.Info(fmt.Sprintf("file: %s removed", app.Path))

		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)
		}
	},
}