package localapi

import (
	"errors"
	"strings"
	"testing"

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

// Test for [AGENT-001]: the inline customer-confirmed wipe must re-resolve the
// confirmed durable id to the current device and refuse if anything changed in
// the window, rather than formatting a mutable /dev path that may now point at a
// different physical disk.
func TestAntiRetargetResolve(t *testing.T) {
	const durable = "byid:wwn-0xCONFIRMED"
	const dev = "/dev/sdb1"

	// probe helpers
	dataBearing := storage.DeviceProbe{Probed: true, HasFilesystem: true, FSType: "ext4"} // DataBearing() true
	blank := storage.DeviceProbe{Probed: true}                                            // Probed, no signatures → not data-bearing
	okInspect := func(string) (storage.DeviceProbe, error) { return dataBearing, nil }

	cases := []struct {
		name    string
		durable string
		resolve func(string) (string, error)
		derive  func(string) (string, error)
		inspect func(string) (storage.DeviceProbe, error)
		wantDev string
		wantErr string // substring; "" = expect success
	}{
		{
			name:    "happy-path-matches",
			durable: durable,
			resolve: func(string) (string, error) { return dev, nil },
			derive:  func(string) (string, error) { return durable, nil },
			inspect: okInspect,
			wantDev: dev,
		},
		{
			name:    "empty-durable-refused",
			durable: "",
			resolve: func(string) (string, error) { return dev, nil },
			derive:  func(string) (string, error) { return durable, nil },
			inspect: okInspect,
			wantErr: "path-only",
		},
		{
			name:    "durable-no-longer-resolves",
			durable: durable,
			resolve: func(string) (string, error) { return "", errors.New("gone") },
			derive:  func(string) (string, error) { return durable, nil },
			inspect: okInspect,
			wantErr: "no longer resolves",
		},
		{
			// THE core AGENT-001 case: the /dev node now points at a DIFFERENT disk,
			// so re-deriving its durable id yields a different value → refuse.
			name:    "retarget-mismatch-refused",
			durable: durable,
			resolve: func(string) (string, error) { return dev, nil },
			derive:  func(string) (string, error) { return "byid:wwn-0xDIFFERENT", nil },
			inspect: okInspect,
			wantErr: "durable-id mismatch",
		},
		{
			name:    "no-longer-data-bearing-refused",
			durable: durable,
			resolve: func(string) (string, error) { return dev, nil },
			derive:  func(string) (string, error) { return durable, nil },
			inspect: func(string) (storage.DeviceProbe, error) { return blank, nil },
			wantErr: "no longer data-bearing",
		},
		{
			name:    "reinspect-error-refused",
			durable: durable,
			resolve: func(string) (string, error) { return dev, nil },
			derive:  func(string) (string, error) { return durable, nil },
			inspect: func(string) (storage.DeviceProbe, error) { return storage.DeviceProbe{}, errors.New("io") },
			wantErr: "re-inspect",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			got, err := antiRetargetResolve(tc.durable, tc.resolve, tc.derive, tc.inspect)
			if tc.wantErr == "" {
				if err != nil {
					t.Fatalf("unexpected error: %v", err)
				}
				if got != tc.wantDev {
					t.Fatalf("device = %q, want %q", got, tc.wantDev)
				}
				return
			}
			if err == nil {
				t.Fatalf("expected refusal containing %q, got device %q and nil error", tc.wantErr, got)
			}
			if !strings.Contains(err.Error(), tc.wantErr) {
				t.Fatalf("error %q does not contain %q", err.Error(), tc.wantErr)
			}
			if got != "" {
				t.Fatalf("on refusal the device must be empty, got %q", got)
			}
		})
	}
}
