package cli

import (
	"bytes"
	"os"
	"path/filepath"
	"strings"
	"testing"

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

func setupBackupTestEnv(t *testing.T) string {
	t.Helper()
	dir := t.TempDir()
	t.Setenv("ORCA_HOME", dir)
	mk, err := secrets.GenerateMasterKey()
	if err != nil {
		t.Fatalf("GenerateMasterKey: %v", err)
	}
	if err := os.MkdirAll(paths.ClusterDir(), 0o755); err != nil {
		t.Fatalf("mkdir cluster dir: %v", err)
	}
	if err := secrets.SaveMasterKey(paths.MasterKeyPath(), mk); err != nil {
		t.Fatalf("SaveMasterKey: %v", err)
	}
	return dir
}

func TestBackupCmdRegistered(t *testing.T) {
	found := false
	for _, cmd := range rootCmd.Commands() {
		if cmd.Name() == "backup" {
			found = true
			break
		}
	}
	if !found {
		t.Fatal("backup command not registered on root")
	}
}

func TestRestoreCmdRegistered(t *testing.T) {
	found := false
	for _, cmd := range rootCmd.Commands() {
		if cmd.Name() == "restore" {
			found = true
			break
		}
	}
	if !found {
		t.Fatal("restore command not registered on root")
	}
}

func TestBackupRestoreCmdRoundTrip(t *testing.T) {
	home := setupBackupTestEnv(t)

	if err := os.WriteFile(filepath.Join(home, "keep.txt"), []byte("payload"), 0o644); err != nil {
		t.Fatalf("write keep.txt: %v", err)
	}

	outDir := t.TempDir()
	out := filepath.Join(outDir, "orca-backup.tar.gz")

	var buf bytes.Buffer
	resetRootFlags(t)
	rootCmd.SetOut(&buf)
	rootCmd.SetErr(&buf)
	rootCmd.SetArgs([]string{"backup", "--out", out})
	if err := rootCmd.Execute(); err != nil {
		t.Fatalf("orca backup: %v", err)
	}
	if _, err := os.Stat(out + ".sig"); err != nil {
		t.Fatalf("sig missing: %v", err)
	}

	target := filepath.Join(t.TempDir(), "restored")
	var buf2 bytes.Buffer
	resetRootFlags(t)
	rootCmd.SetOut(&buf2)
	rootCmd.SetErr(&buf2)
	rootCmd.SetArgs([]string{"restore", "--in", out, "--target", target})
	if err := rootCmd.Execute(); err != nil {
		t.Fatalf("orca restore: %v", err)
	}

	got, err := os.ReadFile(filepath.Join(target, "keep.txt"))
	if err != nil {
		t.Fatalf("restored keep.txt missing: %v", err)
	}
	if string(got) != "payload" {
		t.Errorf("restored keep.txt = %q, want %q", string(got), "payload")
	}
}

func TestRestoreCmdBadSignature(t *testing.T) {
	setupBackupTestEnv(t)

	outDir := t.TempDir()
	out := filepath.Join(outDir, "orca-backup.tar.gz")
	body := []byte("not a real tarball")
	if err := os.WriteFile(out, body, 0o644); err != nil {
		t.Fatalf("write fake tarball: %v", err)
	}
	if err := os.WriteFile(out+".sig", []byte("deadbeef"), 0o644); err != nil {
		t.Fatalf("write fake sig: %v", err)
	}

	target := filepath.Join(t.TempDir(), "restored")
	var buf bytes.Buffer
	resetRootFlags(t)
	rootCmd.SetOut(&buf)
	rootCmd.SetErr(&buf)
	rootCmd.SetArgs([]string{"restore", "--in", out, "--target", target})
	err := rootCmd.Execute()
	if err == nil {
		t.Fatal("restore with bad signature should fail")
	}
}

func TestRestoreCmdRequiresInFlag(t *testing.T) {
	setupBackupTestEnv(t)
	var buf bytes.Buffer
	resetRootFlags(t)
	rootCmd.SetOut(&buf)
	rootCmd.SetErr(&buf)
	rootCmd.SetArgs([]string{"restore"})
	err := rootCmd.Execute()
	if err == nil {
		t.Fatal("restore without --in should fail")
	}
}

func TestBackupCmdDefaultOut(t *testing.T) {
	home := setupBackupTestEnv(t)
	if err := os.WriteFile(filepath.Join(home, "f.txt"), []byte("x"), 0o644); err != nil {
		t.Fatalf("write f.txt: %v", err)
	}

	work := t.TempDir()
	orig, _ := os.Getwd()
	if err := os.Chdir(work); err != nil {
		t.Fatalf("chdir: %v", err)
	}
	defer os.Chdir(orig)

	var buf bytes.Buffer
	resetRootFlags(t)
	rootCmd.SetOut(&buf)
	rootCmd.SetErr(&buf)
	rootCmd.SetArgs([]string{"backup"})
	if err := rootCmd.Execute(); err != nil {
		t.Fatalf("orca backup default out: %v", err)
	}

	entries, err := os.ReadDir(work)
	if err != nil {
		t.Fatalf("read work: %v", err)
	}
	var foundTar, foundSig bool
	for _, e := range entries {
		if e.Name() == "orca-backup" || strings.HasPrefix(e.Name(), "orca-backup-") && strings.HasSuffix(e.Name(), ".tar.gz") {
			foundTar = true
		}
		if strings.HasSuffix(e.Name(), ".tar.gz.sig") {
			foundSig = true
		}
	}
	if !foundTar {
		t.Errorf("default backup tarball not created in CWD (entries: %d)", len(entries))
	}
	if !foundSig {
		t.Errorf("default backup sig not created in CWD (entries: %d)", len(entries))
	}
}
