// Package cli: backup.go implements the `orca backup` and `orca restore`
// subcommands (P04, v0.11 milestone).
//
//	orca backup --out <path>   — create a signed tar.gz of ORCA_HOME
//	orca restore --in <path>   — restore a verified backup
//
// `backup` reads the master key at paths.MasterKeyPath() and backs up
// paths.Root() (ORCA_HOME). The tarball + HMAC-SHA256 signature are
// written to --out and --out+".sig". `restore` verifies the signature
// before extracting; with --force it overwrites a non-empty target.
package cli

import (
	"fmt"
	"time"

	"github.com/spf13/cobra"

	"git.cloudinit.dev/coreci/orca/internal/backup"
	"git.cloudinit.dev/coreci/orca/internal/paths"
	"git.cloudinit.dev/coreci/orca/internal/secrets"
)

var (
	backupOutPath    string
	restoreInPath    string
	restoreTargetDir string
	restoreForce     bool
	restoreDryRun    bool
)

var backupCmd = &cobra.Command{
	Use:   "backup",
	Short: "Create a signed tar.gz backup of ORCA_HOME",
	Long: `Create a signed tar.gz backup of ORCA_HOME (P04).

Walks ` + "`ORCA_HOME`" + ` recursively, excludes /run/orca/*, *.sock,
*.db-wal, *.db-shm, packs the rest into a tar.gz, and computes an
HMAC-SHA256 signature using the cluster master key. The tarball is
written to --out; the hex-encoded signature to --out + ".sig".`,
	Args: cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {
		mk, err := secrets.LoadMasterKey(paths.MasterKeyPath())
		if err != nil {
			return fmt.Errorf("load master key: %w", err)
		}
		out := backupOutPath
		if out == "" {
			ts := time.Now().UTC().Format("20060102-150405")
			out = fmt.Sprintf("orca-backup-%s.tar.gz", ts)
		}
		opts := backup.BackupOptions{
			SourceDir:  paths.Root(),
			OutputPath: out,
			MasterKey:  mk,
		}
		if err := backup.Backup(opts); err != nil {
			return err
		}
		if jsonOutput {
			return printJSON(map[string]string{
				"path": out,
				"sig":  out + ".sig",
			})
		}
		fmt.Fprintf(cmd.OutOrStdout(), "✓ Backup written: %s (sig: %s)\n", out, out+".sig")
		return nil
	},
}

var restoreCmd = &cobra.Command{
	Use:   "restore",
	Short: "Restore ORCA_HOME from a verified signed backup",
	Long: `Restore ORCA_HOME from a verified signed backup (P04/P07).

Verifies the HMAC-SHA256 signature on --in (using the cluster master
key) before extracting. Reconciles with live state: refuses to clobber
running allocations unless --force is given (with --force, stops the
running allocs, extracts, then restarts them from the restored state).
With --dry-run, extracts to a temp dir and reports what WOULD be
restored without touching the real ORCA_HOME. Performs post-restore
verification (master key, namespace dirs, SQLite DBs) and records the
restore in the audit log.`,
	Args: cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {
		if restoreInPath == "" {
			return fmt.Errorf("--in is required")
		}
		mk, err := secrets.LoadMasterKey(paths.MasterKeyPath())
		if err != nil {
			return fmt.Errorf("load master key: %w", err)
		}
		target := restoreTargetDir
		if target == "" {
			target = paths.Root()
		}
		opts := RestoreOptions{
			InputPath: restoreInPath,
			TargetDir: target,
			MasterKey: mk,
			Force:     restoreForce,
			DryRun:    restoreDryRun,
		}
		return runRestore(cmd, opts)
	},
}

func init() {
	backupCmd.Flags().StringVar(&backupOutPath, "out", "", "output tarball path (default: orca-backup-<timestamp>.tar.gz in CWD)")
	restoreCmd.Flags().StringVar(&restoreInPath, "in", "", "input tarball path (required)")
	restoreCmd.Flags().StringVar(&restoreTargetDir, "target", "", "restore target dir (default: ORCA_HOME)")
	restoreCmd.Flags().BoolVar(&restoreForce, "force", false, "overwrite a non-empty target directory and stop+restart running allocs")
	restoreCmd.Flags().BoolVar(&restoreDryRun, "dry-run", false, "extract to a temp dir and report what would be restored without touching ORCA_HOME")
	rootCmd.AddCommand(backupCmd)
	rootCmd.AddCommand(restoreCmd)
}
