package reconcile

import "testing"

// The storage-authorization redesign: a USER-DATA data-bearing wipe is customer-confirmable
// (durable-id-bound, no operator signature); SYSTEM and BACKUP stay operator-signature ONLY, and a
// `confirmed:true` claim on them is REFUSED by role (a compromised controller can't relabel a
// protected device to walk the gate). These assert the gate's tiering — the non-hollow checks the
// spec calls for: "the gate refuses a `confirmed` wipe on system/backup (assert no exec); a user-data
// confirmed wipe binds to the durable id (a mismatched id is refused)".

const durA = "byid:wwn-0x5000c500a"
const durB = "byuuid:1111-2222"

// user-data + confirmed + matching durable id → allowed (customer-confirmable), audited with the id.
func TestStorageWipe_UserDataConfirmed_Allowed(t *testing.T) {
	aud := &captureAudit{}
	g := NewGate(nil, testHost, aud, nil) // NO verifier pinned — proves no operator signature is needed
	d := g.AuthorizeStorageWipe(StorageWipeAuthz{
		HostID: testHost, Role: StorageRoleUserData,
		DeviceDurableID: durA, Confirmed: true, ConfirmDurableID: durA,
	}, nil)
	if !d.Allowed || d.Disposition != CustomerConfirmable || d.Reason != ReasonCustomerConfirmed {
		t.Fatalf("user-data confirmed+matching: got allowed=%v disp=%s reason=%s", d.Allowed, d.Disposition, d.Reason)
	}
	if len(aud.recs) != 1 || !aud.recs[0].Allowed || aud.recs[0].DurableID != durA {
		t.Fatalf("customer-confirmed wipe must be audited with the durable id: %+v", aud.recs)
	}
}

// user-data + confirmed but the confirmation binds to a DIFFERENT disk's durable id → refused
// (binding_mismatch). A confirmation for one disk can't wipe another.
func TestStorageWipe_UserDataDurableMismatch_Refused(t *testing.T) {
	g := NewGate(nil, testHost, &captureAudit{}, nil)
	d := g.AuthorizeStorageWipe(StorageWipeAuthz{
		HostID: testHost, Role: StorageRoleUserData,
		DeviceDurableID: durA, Confirmed: true, ConfirmDurableID: durB, // confirms B, device is A
	}, nil)
	if d.Allowed || d.Reason != ReasonBindingMismatch {
		t.Fatalf("durable-id mismatch: got allowed=%v reason=%s, want refused binding_mismatch", d.Allowed, d.Reason)
	}
}

// user-data + an UNRESOLVABLE device durable id fails safe (refused) even when confirmed.
func TestStorageWipe_UserDataNoDurable_Refused(t *testing.T) {
	g := NewGate(nil, testHost, &captureAudit{}, nil)
	d := g.AuthorizeStorageWipe(StorageWipeAuthz{
		HostID: testHost, Role: StorageRoleUserData,
		DeviceDurableID: "", Confirmed: true, ConfirmDurableID: "",
	}, nil)
	if d.Allowed {
		t.Fatal("a wipe with no resolvable durable id must not be allowed even when confirmed")
	}
}

// user-data, NOT confirmed → pending_confirmation (ask the customer; not a signature).
func TestStorageWipe_UserDataUnconfirmed_PendingConfirmation(t *testing.T) {
	g := NewGate(nil, testHost, &captureAudit{}, nil)
	d := g.AuthorizeStorageWipe(StorageWipeAuthz{
		HostID: testHost, Role: StorageRoleUserData, DeviceDurableID: durA,
	}, nil)
	if d.Allowed || d.Disposition != CustomerConfirmable || d.Reason != ReasonPendingConfirmation {
		t.Fatalf("user-data unconfirmed: got allowed=%v disp=%s reason=%s", d.Allowed, d.Disposition, d.Reason)
	}
}

// THE HEADLINE: a `confirmed:true` wipe on a SYSTEM device is REFUSED — it falls to the
// operator-signature path (no signer pinned → pending_signature), NOT customer-confirmable. The
// customer's confirmation is ignored BY ROLE. Same for BACKUP.
func TestStorageWipe_SystemConfirmedTrue_RefusedBySignature(t *testing.T) {
	for _, role := range []string{StorageRoleSystem, StorageRoleBackup} {
		g := NewGate(nil, testHost, &captureAudit{}, nil)
		d := g.AuthorizeStorageWipe(StorageWipeAuthz{
			HostID: testHost, Role: role,
			DeviceDurableID: durA, Confirmed: true, ConfirmDurableID: durA, // a matching confirmation — must NOT help
		}, nil)
		if d.Allowed {
			t.Fatalf("role=%s: a confirmed wipe of a protected device was ALLOWED — invariant violated", role)
		}
		if d.Disposition != Destructive || d.Reason != ReasonPendingSignature {
			t.Fatalf("role=%s: got disp=%s reason=%s, want destructive/pending_signature", role, d.Disposition, d.Reason)
		}
	}
}

// An UNKNOWN/empty role fails safe to the protected (operator-signature) path, never user-data.
func TestStorageWipe_UnknownRole_FailsSafeDestructive(t *testing.T) {
	g := NewGate(nil, testHost, &captureAudit{}, nil)
	d := g.AuthorizeStorageWipe(StorageWipeAuthz{
		HostID: testHost, Role: "", Confirmed: true, DeviceDurableID: durA, ConfirmDurableID: durA,
	}, nil)
	if d.Allowed || d.Disposition != Destructive {
		t.Fatalf("unknown role must fail safe to destructive: got allowed=%v disp=%s", d.Allowed, d.Disposition)
	}
}
