package app

import (
	"context"
	"fmt"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/log"
	"github.com/urfave/cli/v3"
)

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

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

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

var appBackupListCommand = cli.Command{
	Name:    "list",
	Aliases: []string{"ls"},
	Flags: []cli.Flag{
		snapshotFlag,
		includePathFlag,
	},
	Before:        internal.SubCommandBefore,
	Usage:         "List all backups",
	UsageText:     "abra app backup list <domain> [options]",
	ShellComplete: autocomplete.AppNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		app := internal.ValidateApp(cmd)

		if err := app.Recipe.Ensure(internal.Chaos, internal.Offline); err != nil {
			log.Fatal(err)
		}

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

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

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}
		if includePath != "" {
			log.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 {
			log.Fatal(err)
		}

		return nil
	},
}

var appBackupDownloadCommand = cli.Command{
	Name:    "download",
	Aliases: []string{"d"},
	Flags: []cli.Flag{
		snapshotFlag,
		includePathFlag,
	},
	Before:        internal.SubCommandBefore,
	Usage:         "Download a backup",
	UsageText:     "abra app backup download <domain> [options]",
	ShellComplete: autocomplete.AppNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		app := internal.ValidateApp(cmd)

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

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

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

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

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

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

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}
		if includePath != "" {
			log.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 {
			log.Fatal(err)
		}

		remoteBackupDir := "/tmp/backup.tar.gz"
		currentWorkingDir := "."
		if err = CopyFromContainer(cl, targetContainer.ID, remoteBackupDir, currentWorkingDir); err != nil {
			log.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{
		resticRepoFlag,
	},
	Before:        internal.SubCommandBefore,
	Usage:         "Create a new backup",
	UsageText:     "abra app backup create <domain> [options]",
	ShellComplete: autocomplete.AppNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		app := internal.ValidateApp(cmd)

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

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

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

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

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

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

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if resticRepo != "" {
			log.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 {
			log.Fatal(err)
		}

		return nil
	},
}

var appBackupSnapshotsCommand = cli.Command{
	Name:    "snapshots",
	Aliases: []string{"s"},
	Flags: []cli.Flag{
		snapshotFlag,
	},
	Before:        internal.SubCommandBefore,
	Usage:         "List backup snapshots",
	UsageText:     "abra app backup snapshots <domain> [options]",
	ShellComplete: autocomplete.AppNameComplete,
	HideHelp:      true,
	Action: func(ctx context.Context, cmd *cli.Command) error {
		app := internal.ValidateApp(cmd)

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

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

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

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

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

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

		execEnv := []string{fmt.Sprintf("SERVICE=%s", app.Domain)}
		if snapshot != "" {
			log.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 {
			log.Fatal(err)
		}

		return nil
	},
}

var appBackupCommand = cli.Command{
	Name:      "backup",
	Aliases:   []string{"b"},
	Usage:     "Manage app backups",
	UsageText: "abra app backup [command] [arguments] [options]",
	Commands: []*cli.Command{
		&appBackupListCommand,
		&appBackupSnapshotsCommand,
		&appBackupDownloadCommand,
		&appBackupCreateCommand,
	},
}
