package reconcile

import (
	"strings"
	"testing"
)

// (TestArchiveVMID + TestBindMountOverrides were deleted with their subjects in v0.76.0/GL-5b —
// the restore-test now derives its params from the ARCHIVE's embedded config via
// drRestoreOverrides; the live-source-config path was the pre-fix shape.)

func TestRootfsSizeGB(t *testing.T) {
	cases := map[string]int{
		"local-lvm:vm-9201-disk-0,size=8G": 8,
		"local-lvm:base,size=512M":         1, // rounds up
		"local-lvm:base,size=1T":           1024,
		"local-lvm:base,size=0":            0,
		"local-lvm:base":                   0, // no size field
		"local-lvm:base,size=8":            8, // unit-less → GB
	}
	for spec, want := range cases {
		if got := rootfsSizeGB(spec); got != want {
			t.Errorf("rootfsSizeGB(%q) = %d, want %d", spec, got, want)
		}
	}
}

// GL-5b: the mount-parity comparator — the assert that keeps PVE's drop-unlisted-mountpoints rule
// from regressing into a green light. Pure-function cases; the engine-level Scenario A/B live in
// restoretest_test.go / the fake-driven tests.
func TestMountParity(t *testing.T) {
	archive := map[string]string{
		"hostname": "demo",
		"rootfs":   "local-lvm:vm-9201-disk-0,size=32G",
		"mp0":      "local-lvm:vm-9201-disk-1,mp=/var/lib/docker,backup=1,size=200G",
		"mp1":      "local-lvm:vm-9201-disk-2,mp=/mnt/sys_drive,backup=1,size=50G",
		"mp8":      "/mnt/felhom-drives,mp=/mnt/felhom-drives",
		"mp9":      "/var/lib/felhom-agent/guests/9201/bootstrap,mp=/etc/felhom-bootstrap,ro=1",
	}

	// full parity: storage mpN at archived path+size, binds as throwaway stand-ins
	restored := map[string]string{
		"mp0": "local-lvm:vm-990000-disk-1,mp=/var/lib/docker,backup=1,size=200G",
		"mp1": "local-lvm:vm-990000-disk-2,mp=/mnt/sys_drive,backup=1,size=50G",
		"mp8": "local-lvm:vm-990000-disk-3,mp=/mnt/felhom-drives,backup=0,size=1G",
		"mp9": "local-lvm:vm-990000-disk-4,mp=/etc/felhom-bootstrap,backup=0,size=1G",
	}
	inv, delta := mountParity(archive, restored)
	if len(delta) != 0 {
		t.Fatalf("full parity expected, got delta: %v", delta)
	}
	if len(inv) != 4 {
		t.Fatalf("inventory must carry all 4 verified mpN, got %v", inv)
	}

	// the GL-5 constraint-(b) shape: a storage mpN silently dropped → NAMED delta (Scenario B core)
	dropped := map[string]string{
		"mp1": restored["mp1"], "mp8": restored["mp8"], "mp9": restored["mp9"],
	}
	_, delta = mountParity(archive, dropped)
	if len(delta) != 1 || !strings.Contains(delta[0], "mp0 MISSING") {
		t.Fatalf("dropped mp0 must be a named delta, got %v", delta)
	}

	// wrong path
	wrongPath := map[string]string{
		"mp0": "local-lvm:vm-990000-disk-1,mp=/elsewhere,size=200G",
		"mp1": restored["mp1"], "mp8": restored["mp8"], "mp9": restored["mp9"],
	}
	_, delta = mountParity(archive, wrongPath)
	if len(delta) != 1 || !strings.Contains(delta[0], `mp0 path "/elsewhere"`) {
		t.Fatalf("wrong path must be a named delta, got %v", delta)
	}

	// undersized volume (a 1G stand-in where 200G of data should be = the dropped-content shape)
	small := map[string]string{
		"mp0": "local-lvm:vm-990000-disk-1,mp=/var/lib/docker,size=1G",
		"mp1": restored["mp1"], "mp8": restored["mp8"], "mp9": restored["mp9"],
	}
	_, delta = mountParity(archive, small)
	if len(delta) != 1 || !strings.Contains(delta[0], "mp0 size 1G < archive 200G") {
		t.Fatalf("undersized mpN must be a named delta, got %v", delta)
	}

	// an extra restored mpN the archive never had is a delta too
	extra := map[string]string{
		"mp0": restored["mp0"], "mp1": restored["mp1"], "mp8": restored["mp8"], "mp9": restored["mp9"],
		"mp3": "local-lvm:vm-990000-disk-9,mp=/stray,size=1G",
	}
	_, delta = mountParity(archive, extra)
	if len(delta) != 1 || !strings.Contains(delta[0], "mp3 present on the restored guest but not in the archive") {
		t.Fatalf("extra mpN must be a named delta, got %v", delta)
	}

	// no mpN anywhere = trivially parity (the golden-shaped archive)
	inv, delta = mountParity(map[string]string{"rootfs": "l:d,size=8G"}, map[string]string{})
	if len(delta) != 0 || len(inv) != 0 {
		t.Fatalf("mpN-less archive must be trivial parity, got inv=%v delta=%v", inv, delta)
	}
}
