package backup

import (
	"context"
	"testing"

	"gitea.dooplex.hu/admin/felhom-agent/internal/config"
	"gitea.dooplex.hu/admin/felhom-agent/internal/proxmox"
)

// localTarget is a non-PBS dir storage; pbsTarget is a PBS storage — for the scope gate.
var (
	localTargetStores = []proxmox.Storage{{Storage: "local", Type: "dir", Content: "backup"}}
	pbsTargetStores   = []proxmox.Storage{{Storage: "felhom-pbs", Type: "pbs", Content: "backup"}}
)

func okAPI(stores []proxmox.Storage) *fakeBackupAPI {
	return &fakeBackupAPI{vzdumpUPID: "UPID:vzdump:1", storages: stores}
}

// TestPrune_LocalCarriesKeepLast: a LOCAL-target backup with retention carries `--prune-backups
// keep-last=3` on the vzdump. Companion: the SAME runner built with no retention ("") emits NO prune
// option — proving the flag only rides when retention is set (a no-prune build accumulates).
func TestPrune_LocalCarriesKeepLast(t *testing.T) {
	api := okAPI(localTargetStores)
	r := NewBackupRunner(api, "local", proxmox.ModeStop, "", "keep-last=3", quiet())
	_, _ = r.Backup(context.Background(), 9201) // archive-resolution may fail in the fake; we assert the captured vzdump opts
	if len(api.vzdumps) != 1 || api.vzdumps[0].PruneBackups != "keep-last=3" {
		t.Fatalf("local backup must carry prune-backups keep-last=3, got %q", api.vzdumps[0].PruneBackups)
	}

	// COMPANION: no retention → no prune option (dumps would accumulate).
	api2 := okAPI(localTargetStores)
	r2 := NewBackupRunner(api2, "local", proxmox.ModeStop, "", "", quiet())
	_, _ = r2.Backup(context.Background(), 9201)
	if api2.vzdumps[0].PruneBackups != "" {
		t.Fatalf("a no-retention runner must NOT prune, got %q", api2.vzdumps[0].PruneBackups)
	}
}

// TestPrune_NeverPrunesPBS is the scope rule (§9): retention is NOT applied when the target is a PBS
// storage (offsite retention is a separate lifecycle). Companion: the identical retention on a LOCAL
// target IS applied — proving the gate keys on storage type, not luck.
func TestPrune_NeverPrunesPBS(t *testing.T) {
	api := okAPI(pbsTargetStores)
	r := NewBackupRunner(api, "felhom-pbs", proxmox.ModeStop, "", "keep-last=3", quiet())
	_, _ = r.Backup(context.Background(), 9201)
	if api.vzdumps[0].PruneBackups != "" {
		t.Fatalf("a PBS target must NEVER be pruned by the per-run flag, got %q", api.vzdumps[0].PruneBackups)
	}

	// COMPANION: same retention, local target → applied.
	api2 := okAPI(localTargetStores)
	r2 := NewBackupRunner(api2, "local", proxmox.ModeStop, "", "keep-last=3", quiet())
	_, _ = r2.Backup(context.Background(), 9201)
	if api2.vzdumps[0].PruneBackups != "keep-last=3" {
		t.Fatalf("control: a local target with the same retention MUST be pruned, got %q", api2.vzdumps[0].PruneBackups)
	}
}

// TestPrune_FailSafeOnUnknownTarget: if the target's type can't be confirmed (lookup error / not in the
// list), the run SKIPS pruning rather than risk pruning a PBS/unknown storage.
func TestPrune_FailSafeOnUnknownTarget(t *testing.T) {
	// target not present in the list → skip.
	api := &fakeBackupAPI{vzdumpUPID: "UPID:vzdump:1", storages: localTargetStores}
	r := NewBackupRunner(api, "some-other-store", proxmox.ModeStop, "", "keep-last=3", quiet())
	_, _ = r.Backup(context.Background(), 9201)
	if api.vzdumps[0].PruneBackups != "" {
		t.Fatalf("an unknown target must skip pruning (fail-safe), got %q", api.vzdumps[0].PruneBackups)
	}
}

// TestPrune_KeepLastClamp (§7-B): a 0/negative/unset LocalBackupRetention clamps to ≥1 (default 3) so the
// vzdump NEVER prunes the archive it just made. Companion: a no-clamp impl that returns 0 would emit
// keep-last=0 → PVE prunes everything → FAILS the "≥1" assertion.
func TestPrune_KeepLastClamp(t *testing.T) {
	cases := []struct {
		set  int
		want int
	}{
		{0, 3},   // unset → default
		{-5, 3},  // negative → default
		{1, 1},   // honored
		{3, 3},   // honored
		{10, 10}, // honored
	}
	for _, c := range cases {
		b := config.BackupConfig{LocalBackupRetention: c.set}
		if got := b.KeepLast(); got != c.want {
			t.Errorf("KeepLast(%d) = %d, want %d", c.set, got, c.want)
		}
		if b.KeepLast() < 1 {
			t.Fatalf("keep-last must NEVER be < 1 (would prune the fresh backup), got %d for %d", b.KeepLast(), c.set)
		}
	}
	if spec := (config.BackupConfig{}).PruneBackupsSpec(); spec != "keep-last=3" {
		t.Fatalf("default PruneBackupsSpec = %q, want keep-last=3", spec)
	}
}
