package app

import (
	"fmt"

	"coopcloud.tech/abra/cli/internal"
	"coopcloud.tech/abra/pkg/autocomplete"
	"coopcloud.tech/abra/pkg/client"
	"coopcloud.tech/abra/pkg/log"
	"github.com/spf13/cobra"
)

var AppBackupListCommand = &cobra.Command{
	Use:     "list <app> [flags]",
	Aliases: []string{"ls"},
	Short:   "List the contents of a snapshot",
	Args:    cobra.ExactArgs(1),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		return autocomplete.AppNameComplete()
	},
	Run: func(cmd *cobra.Command, args []string) {
		app := internal.ValidateApp(args)

		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),
			"MACHINE_LOGS=true",
		}

		if snapshot != "" {
			log.Debugf("including SNAPSHOT=%s in backupbot exec invocation", snapshot)
			execEnv = append(execEnv, fmt.Sprintf("SNAPSHOT=%s", snapshot))
		}

		if showAllPaths {
			log.Debugf("including SHOW_ALL=%v in backupbot exec invocation", showAllPaths)
			execEnv = append(execEnv, fmt.Sprintf("SHOW_ALL=%v", showAllPaths))
		}

		if timestamps {
			log.Debugf("including TIMESTAMPS=%v in backupbot exec invocation", timestamps)
			execEnv = append(execEnv, fmt.Sprintf("TIMESTAMPS=%v", timestamps))
		}

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

var AppBackupDownloadCommand = &cobra.Command{
	Use:     "download <app> [flags]",
	Aliases: []string{"d"},
	Short:   "Download a snapshot",
	Long: `Downloads a backup.tar.gz to the current working directory.

"--volumes/-v" includes data contained in volumes alongide paths specified in
"backupbot.backup.path" labels.`,
	Args: cobra.ExactArgs(1),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		return autocomplete.AppNameComplete()
	},
	Run: func(cmd *cobra.Command, args []string) {
		app := internal.ValidateApp(args)

		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),
			"MACHINE_LOGS=true",
		}

		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 includeSecrets {
			log.Debugf("including SECRETS=%v in backupbot exec invocation", includeSecrets)
			execEnv = append(execEnv, fmt.Sprintf("SECRETS=%v", includeSecrets))
		}

		if includeVolumes {
			log.Debugf("including VOLUMES=%v in backupbot exec invocation", includeVolumes)
			execEnv = append(execEnv, fmt.Sprintf("VOLUMES=%v", includeVolumes))
		}

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

var AppBackupCreateCommand = &cobra.Command{
	Use:     "create <app> [flags]",
	Aliases: []string{"c"},
	Short:   "Create a new snapshot",
	Args:    cobra.ExactArgs(1),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		return autocomplete.AppNameComplete()
	},
	Run: func(cmd *cobra.Command, args []string) {
		app := internal.ValidateApp(args)

		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),
			"MACHINE_LOGS=true",
		}

		if retries != "" {
			log.Debugf("including RETRIES=%s in backupbot exec invocation", retries)
			execEnv = append(execEnv, fmt.Sprintf("RETRIES=%s", retries))
		}

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

var AppBackupSnapshotsCommand = &cobra.Command{
	Use:     "snapshots <app> [flags]",
	Aliases: []string{"s"},
	Short:   "List all snapshots",
	Args:    cobra.ExactArgs(1),
	ValidArgsFunction: func(
		cmd *cobra.Command,
		args []string,
		toComplete string) ([]string, cobra.ShellCompDirective) {
		return autocomplete.AppNameComplete()
	},
	Run: func(cmd *cobra.Command, args []string) {
		app := internal.ValidateApp(args)

		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),
			"MACHINE_LOGS=true",
		}

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

var AppBackupCommand = &cobra.Command{
	Use:     "backup [cmd] [args] [flags]",
	Aliases: []string{"b"},
	Short:   "Manage app backups",
}

var (
	snapshot       string
	retries        string
	includePath    string
	showAllPaths   bool
	timestamps     bool
	includeSecrets bool
	includeVolumes bool
)

func init() {
	AppBackupListCommand.Flags().StringVarP(
		&snapshot,
		"snapshot",
		"s",
		"",
		"list specific snapshot",
	)

	AppBackupListCommand.Flags().BoolVarP(
		&showAllPaths,
		"all",
		"a",
		false,
		"show all paths",
	)

	AppBackupListCommand.Flags().BoolVarP(
		&timestamps,
		"timestamps",
		"t",
		false,
		"include timestamps",
	)

	AppBackupDownloadCommand.Flags().StringVarP(
		&snapshot,
		"snapshot",
		"s",
		"",
		"list specific snapshot",
	)

	AppBackupDownloadCommand.Flags().StringVarP(
		&includePath,
		"path",
		"p",
		"",
		"volumes path",
	)

	AppBackupDownloadCommand.Flags().BoolVarP(
		&includeSecrets,
		"secrets",
		"S",
		false,
		"include secrets",
	)

	AppBackupDownloadCommand.Flags().BoolVarP(
		&includeVolumes,
		"volumes",
		"v",
		false,
		"include volumes",
	)

	AppBackupDownloadCommand.Flags().BoolVarP(
		&internal.Chaos,
		"chaos",
		"C",
		false,
		"ignore uncommitted recipes changes",
	)

	AppBackupCreateCommand.Flags().StringVarP(
		&retries,
		"retries",
		"r",
		"1",
		"number of retry attempts",
	)

	AppBackupCreateCommand.Flags().BoolVarP(
		&internal.Chaos,
		"chaos",
		"C",
		false,
		"ignore uncommitted recipes changes",
	)
}