package app

import (
	"fmt"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/recipe"
	"github.com/sirupsen/logrus"
	"github.com/urfave/cli"
)

var snapshot string
var snapshotFlag = &cli.StringFlag{
	Name:        "snapshot, s",
	Usage:       "Lists specific snapshot",
	Destination: &snapshot,
}

var includePath string
var includePathFlag = &cli.StringFlag{
	Name:        "path, p",
	Usage:       "Include path",
	Destination: &includePath,
}

var resticRepo string
var resticRepoFlag = &cli.StringFlag{
	Name:        "repo, r",
	Usage:       "Restic repository",
	Destination: &resticRepo,
}

var appBackupListCommand = cli.Command{
	Name:    "list",
	Aliases: []string{"ls"},
	Flags: []cli.Flag{
		internal.DebugFlag,
		internal.OfflineFlag,
		snapshotFlag,
		includePathFlag,
	},
	Before:       internal.SubCommandBefore,
	Usage:        "List all backups",
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if err := recipe.EnsureExists(app.Recipe); err != nil {
			logrus.Fatal(err)
		}

		if !internal.Chaos {
			if err := recipe.EnsureIsClean(app.Recipe); err != nil {
				logrus.Fatal(err)
			}

			if !internal.Offline {
				if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
					logrus.Fatal(err)
				}
			}

			if err := recipe.EnsureLatest(app.Recipe); err != nil {
				logrus.Fatal(err)
			}
		}

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

		targetContainer, err := internal.RetrieveBackupBotContainer(cl)
		if err != nil {
			logrus.Fatal(err)
		}

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			logrus.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}
		if includePath != "" {
			logrus.Debugf("including INCLUDE_PATH=%s in backupbot exec invocation", includePath)
			execEnv = append(execEnv, fmt.Sprintf("INCLUDE_PATH=%s", includePath))
		}

		if err := internal.RunBackupCmdRemote(cl, "ls", targetContainer.ID, execEnv); err != nil {
			logrus.Fatal(err)
		}

		return nil
	},
}

var appBackupDownloadCommand = cli.Command{
	Name:    "download",
	Aliases: []string{"d"},
	Flags: []cli.Flag{
		internal.DebugFlag,
		internal.OfflineFlag,
		snapshotFlag,
		includePathFlag,
	},
	Before:       internal.SubCommandBefore,
	Usage:        "Download a backup",
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if err := recipe.EnsureExists(app.Recipe); err != nil {
			logrus.Fatal(err)
		}

		if !internal.Chaos {
			if err := recipe.EnsureIsClean(app.Recipe); err != nil {
				logrus.Fatal(err)
			}

			if !internal.Offline {
				if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
					logrus.Fatal(err)
				}
			}

			if err := recipe.EnsureLatest(app.Recipe); err != nil {
				logrus.Fatal(err)
			}
		}

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

		targetContainer, err := internal.RetrieveBackupBotContainer(cl)
		if err != nil {
			logrus.Fatal(err)
		}

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			logrus.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}
		if includePath != "" {
			logrus.Debugf("including INCLUDE_PATH=%s in backupbot exec invocation", includePath)
			execEnv = append(execEnv, fmt.Sprintf("INCLUDE_PATH=%s", includePath))
		}

		if err := internal.RunBackupCmdRemote(cl, "download", targetContainer.ID, execEnv); err != nil {
			logrus.Fatal(err)
		}

		remoteBackupDir := "/tmp/backup.tar.gz"
		currentWorkingDir := "."
		if err = CopyFromContainer(cl, targetContainer.ID, remoteBackupDir, currentWorkingDir); err != nil {
			logrus.Fatal(err)
		}

		fmt.Println("backup successfully downloaded to current working directory")

		return nil
	},
}

var appBackupCreateCommand = cli.Command{
	Name:    "create",
	Aliases: []string{"c"},
	Flags: []cli.Flag{
		internal.DebugFlag,
		internal.OfflineFlag,
		resticRepoFlag,
	},
	Before:       internal.SubCommandBefore,
	Usage:        "Create a new backup",
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if err := recipe.EnsureExists(app.Recipe); err != nil {
			logrus.Fatal(err)
		}

		if !internal.Chaos {
			if err := recipe.EnsureIsClean(app.Recipe); err != nil {
				logrus.Fatal(err)
			}

			if !internal.Offline {
				if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
					logrus.Fatal(err)
				}
			}

			if err := recipe.EnsureLatest(app.Recipe); err != nil {
				logrus.Fatal(err)
			}
		}

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

		targetContainer, err := internal.RetrieveBackupBotContainer(cl)
		if err != nil {
			logrus.Fatal(err)
		}

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if resticRepo != "" {
			logrus.Debugf("including RESTIC_REPO=%s in backupbot exec invocation", resticRepo)
			execEnv = append(execEnv, fmt.Sprintf("RESTIC_REPO=%s", resticRepo))
		}

		if err := internal.RunBackupCmdRemote(cl, "create", targetContainer.ID, execEnv); err != nil {
			logrus.Fatal(err)
		}

		return nil
	},
}

var appBackupSnapshotsCommand = cli.Command{
	Name:    "snapshots",
	Aliases: []string{"s"},
	Flags: []cli.Flag{
		internal.DebugFlag,
		internal.OfflineFlag,
		snapshotFlag,
	},
	Before:       internal.SubCommandBefore,
	Usage:        "List backup snapshots",
	BashComplete: autocomplete.AppNameComplete,
	Action: func(c *cli.Context) error {
		app := internal.ValidateApp(c)

		if err := recipe.EnsureExists(app.Recipe); err != nil {
			logrus.Fatal(err)
		}

		if !internal.Chaos {
			if err := recipe.EnsureIsClean(app.Recipe); err != nil {
				logrus.Fatal(err)
			}

			if !internal.Offline {
				if err := recipe.EnsureUpToDate(app.Recipe); err != nil {
					logrus.Fatal(err)
				}
			}

			if err := recipe.EnsureLatest(app.Recipe); err != nil {
				logrus.Fatal(err)
			}
		}

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

		targetContainer, err := internal.RetrieveBackupBotContainer(cl)
		if err != nil {
			logrus.Fatal(err)
		}

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			logrus.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}

		if err := internal.RunBackupCmdRemote(cl, "snapshots", targetContainer.ID, execEnv); err != nil {
			logrus.Fatal(err)
		}

		return nil
	},
}

var appBackupCommand = cli.Command{
	Name:      "backup",
	Aliases:   []string{"b"},
	Usage:     "Manage app backups",
	ArgsUsage: "<domain>",
	Subcommands: []cli.Command{
		appBackupListCommand,
		appBackupSnapshotsCommand,
		appBackupDownloadCommand,
		appBackupCreateCommand,
	},
}