package catalogverificationtx

import (
	"context"
	"database/sql"
	"database/sql/driver"
	"errors"
	"strings"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	layoutbundlekeyv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/layoutbundlekeyv1"
	systemauthorityv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/systemlayoutbundleauthorityv1"
)

const (
	testSystemCreateCommand = systemauthorityv1.CommandID(
		"018f0000-0000-7000-9000-000000000021",
	)
	testSystemRetireCommand = systemauthorityv1.CommandID(
		"018f0000-0000-7000-9000-000000000022",
	)
	testSystemPrincipalID = "catalog-system-slot-writer"
)

func TestVerifySystemOwnerLocksAndValidatesCompleteActiveLineage(t *testing.T) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	request := validSystemOwnerRequest()
	slot := validSystemActiveSlot(request)
	slotDigest := mustSystemSlotDigest(t, slot)
	create := validSystemCreateCommand(t, request, slot)

	expectSystemFenceAcquire(mock, 1)
	expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
	expectSystemHistory(mock, systemHistory{
		commandID: testSystemCreateCommand,
		ordinal:   1,
		slot:      slot,
		digest:    slotDigest,
	})
	expectSystemCommands(mock, request, create)
	expectSystemOutcome(mock, create, "APPLIED")

	fact, err := VerifySystemOwner(context.Background(), token, db, request)
	if err != nil {
		t.Fatal(err)
	}
	if fact.Slot != slot || fact.SlotDigest != slotDigest {
		t.Fatalf("system owner fact = %#v", fact)
	}

	mock.ExpectRollback()
	expectSystemFenceRelease(mock, 1)
	expectSystemSessionRestore(mock)
	if err := token.Close(); err != nil {
		t.Fatal(err)
	}
	assertVerificationExpectations(t, mock)
}

func TestVerifySystemOwnerClaimUsesOpaquePendingClaim(t *testing.T) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	request := validSystemOwnerRequest()
	required := requiredBundleKeySetForTest(request.BundleKey)
	slot := validSystemActiveSlot(request)
	slotDigest := mustSystemSlotDigest(t, slot)
	create := validSystemCreateCommand(t, request, slot)
	sourceIdentity := sourceIdentityForRequiredSetTest(t, required)
	if err := bindOwnedSourceForTest(token, sourceIdentity); err != nil {
		t.Fatal(err)
	}
	lease, err := NewLease(token, required)
	if err != nil {
		t.Fatal(err)
	}
	claim, err := lease.BeginSystemClaim(
		0,
		SystemSourceFacts{
			SourceCatalogSnapshot:       sourceIdentity.catalogSnapshot,
			OrgID:                       sourceIdentity.orgID,
			WriterCommandID:             sourceIdentity.writerCommandID,
			WriterReservationGeneration: sourceIdentity.writerReservationGeneration,
			SourceRequestDigest:         sourceIdentity.sourceRequestDigest,
			RequiredBundleKeySetDigest:  sourceIdentity.requiredBundleKeySetDigest,
			BundleKey:                   request.BundleKey,
		},
		request,
	)
	if err != nil {
		t.Fatal(err)
	}

	expectSystemFenceAcquire(mock, 1)
	expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
	expectSystemHistory(mock, systemHistory{
		commandID: testSystemCreateCommand,
		ordinal:   1,
		slot:      slot,
		digest:    slotDigest,
	})
	expectSystemCommands(mock, request, create)
	expectSystemOutcome(mock, create, "APPLIED")

	fact, err := VerifySystemOwnerClaim(context.Background(), db, claim)
	if err != nil {
		t.Fatal(err)
	}
	if fact.Slot != slot || fact.SlotDigest != slotDigest {
		t.Fatalf("system owner fact = %#v", fact)
	}
	if _, err := VerifySystemOwnerClaim(
		context.Background(),
		db,
		claim,
	); !errors.Is(err, ErrClosed) {
		t.Fatalf("system claim verification replay = %v, want ErrClosed", err)
	}
	expectSystemFenceOwnership(mock)
	if err := CompleteSystemClaim(
		claim,
		receiptForSystemFacts(claim.facts),
	); err != nil {
		t.Fatal(err)
	}
	if err := CompleteSystemClaim(
		claim,
		receiptForSystemFacts(claim.facts),
	); !errors.Is(err, ErrClosed) {
		t.Fatalf("second system claim completion = %v, want ErrClosed", err)
	}
	expectSystemFenceOwnership(mock)
	if !claim.Active() {
		t.Fatal("completed system claim is not active")
	}

	mock.ExpectRollback()
	expectSystemFenceRelease(mock, 1)
	expectSystemSessionRestore(mock)
	if err := lease.Close(); err != nil {
		t.Fatal(err)
	}
	if claim.Active() {
		t.Fatal("system claim remained active after source lease close")
	}
	assertVerificationExpectations(t, mock)
}

func TestVerifySystemOwnerAllowsFailedRetireButRejectsAppliedRetire(
	t *testing.T,
) {
	for _, test := range []struct {
		name       string
		retire     string
		wantErr    error
		errSnippet string
	}{
		{
			name:   "failed retirement is not a lifecycle transition",
			retire: "EXPECTED_PRIOR_MISMATCH",
		},
		{
			name:       "applied retirement conflicts with active state",
			retire:     "APPLIED",
			wantErr:    ErrSystemOwnerCorrupt,
			errSnippet: "APPLIED retirement",
		},
	} {
		t.Run(test.name, func(t *testing.T) {
			db, mock, token := newOwnedVerificationToken(t)
			defer db.Close()
			request := validSystemOwnerRequest()
			slot := validSystemActiveSlot(request)
			slotDigest := mustSystemSlotDigest(t, slot)
			create := validSystemCreateCommand(t, request, slot)
			retire := validSystemRetireCommand(t, request, slot, slotDigest)

			expectSystemFenceAcquire(mock, 1)
			expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
			expectSystemHistory(mock, systemHistory{
				commandID: testSystemCreateCommand,
				ordinal:   1,
				slot:      slot,
				digest:    slotDigest,
			})
			expectSystemCommands(mock, request, create, retire)
			expectSystemOutcome(mock, create, "APPLIED")
			expectSystemOutcome(mock, retire, test.retire)

			fact, err := VerifySystemOwner(
				context.Background(),
				token,
				db,
				request,
			)
			if test.wantErr == nil {
				if err != nil {
					t.Fatal(err)
				}
				if fact.Slot != slot || fact.SlotDigest != slotDigest {
					t.Fatalf("system owner fact = %#v", fact)
				}
			} else {
				if !errors.Is(err, test.wantErr) ||
					!strings.Contains(err.Error(), test.errSnippet) {
					t.Fatalf(
						"VerifySystemOwner error = %v, want %v containing %q",
						err,
						test.wantErr,
						test.errSnippet,
					)
				}
			}

			mock.ExpectRollback()
			expectSystemFenceRelease(mock, 1)
			expectSystemSessionRestore(mock)
			if err := token.Close(); err != nil {
				t.Fatal(err)
			}
			assertVerificationExpectations(t, mock)
		})
	}
}

func TestVerifySystemOwnerRejectsMissingOrRetiredCurrent(t *testing.T) {
	t.Run("missing", func(t *testing.T) {
		db, mock, token := newOwnedVerificationToken(t)
		defer db.Close()
		request := validSystemOwnerRequest()
		expectSystemFenceAcquire(mock, 1)
		mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlot.*FOR UPDATE`).
			WithArgs(systemKeyArgs(request)...).
			WillReturnRows(sqlmock.NewRows(systemCurrentColumns()))

		if _, err := VerifySystemOwner(
			context.Background(),
			token,
			db,
			request,
		); !errors.Is(err, ErrSystemOwnerNotFound) {
			t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerNotFound", err)
		}

		mock.ExpectRollback()
		expectSystemFenceRelease(mock, 1)
		expectSystemSessionRestore(mock)
		if err := token.Close(); err != nil {
			t.Fatal(err)
		}
		assertVerificationExpectations(t, mock)
	})

	t.Run("retired", func(t *testing.T) {
		db, mock, token := newOwnedVerificationToken(t)
		defer db.Close()
		request := validSystemOwnerRequest()
		slot := validSystemActiveSlot(request)
		slot.State = systemauthorityv1.SlotStateTombstone
		expectSystemFenceAcquire(mock, 1)
		expectSystemCurrent(
			mock,
			slot,
			mustSystemSlotDigest(t, slot),
			testSystemRetireCommand,
		)

		if _, err := VerifySystemOwner(
			context.Background(),
			token,
			db,
			request,
		); !errors.Is(err, ErrSystemOwnerConflict) {
			t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerConflict", err)
		}

		mock.ExpectRollback()
		expectSystemFenceRelease(mock, 1)
		expectSystemSessionRestore(mock)
		if err := token.Close(); err != nil {
			t.Fatal(err)
		}
		assertVerificationExpectations(t, mock)
	})
}

func TestVerifySystemOwnerRejectsIncompleteCreationHistory(t *testing.T) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	request := validSystemOwnerRequest()
	slot := validSystemActiveSlot(request)
	slotDigest := mustSystemSlotDigest(t, slot)

	expectSystemFenceAcquire(mock, 1)
	expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
	mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlotHistory.*ORDER BY TransitionOrdinal FOR UPDATE`).
		WithArgs(systemKeyArgs(request)...).
		WillReturnRows(sqlmock.NewRows(systemHistoryColumns()))

	if _, err := VerifySystemOwner(
		context.Background(),
		token,
		db,
		request,
	); !errors.Is(err, ErrSystemOwnerCorrupt) {
		t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerCorrupt", err)
	}

	mock.ExpectRollback()
	expectSystemFenceRelease(mock, 1)
	expectSystemSessionRestore(mock)
	if err := token.Close(); err != nil {
		t.Fatal(err)
	}
	assertVerificationExpectations(t, mock)
}

func TestVerifySystemOwnerRejectsCurrentDigestDrift(t *testing.T) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	request := validSystemOwnerRequest()
	slot := validSystemActiveSlot(request)

	expectSystemFenceAcquire(mock, 1)
	expectSystemCurrent(
		mock,
		slot,
		systemOwnerDigest("f"),
		testSystemCreateCommand,
	)
	if _, err := VerifySystemOwner(
		context.Background(),
		token,
		db,
		request,
	); !errors.Is(err, ErrSystemOwnerCorrupt) {
		t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerCorrupt", err)
	}

	mock.ExpectRollback()
	expectSystemFenceRelease(mock, 1)
	expectSystemSessionRestore(mock)
	if err := token.Close(); err != nil {
		t.Fatal(err)
	}
	assertVerificationExpectations(t, mock)
}

func TestVerifySystemOwnerRejectsDuplicateCreationLineage(t *testing.T) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	request := validSystemOwnerRequest()
	slot := validSystemActiveSlot(request)
	slotDigest := mustSystemSlotDigest(t, slot)
	tombstone := slot
	tombstone.State = systemauthorityv1.SlotStateTombstone

	expectSystemFenceAcquire(mock, 1)
	expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
	expectSystemHistory(
		mock,
		systemHistory{
			commandID: testSystemCreateCommand,
			ordinal:   1,
			slot:      slot,
			digest:    slotDigest,
		},
		systemHistory{
			commandID: testSystemRetireCommand,
			ordinal:   2,
			slot:      tombstone,
			digest:    mustSystemSlotDigest(t, tombstone),
			prior: sql.NullString{
				String: slotDigest,
				Valid:  true,
			},
		},
	)
	if _, err := VerifySystemOwner(
		context.Background(),
		token,
		db,
		request,
	); !errors.Is(err, ErrSystemOwnerCorrupt) {
		t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerCorrupt", err)
	}

	mock.ExpectRollback()
	expectSystemFenceRelease(mock, 1)
	expectSystemSessionRestore(mock)
	if err := token.Close(); err != nil {
		t.Fatal(err)
	}
	assertVerificationExpectations(t, mock)
}

func TestVerifySystemOwnerRejectsCreationCommandAndOutcomeCorruption(
	t *testing.T,
) {
	for _, test := range []struct {
		name string
		kind string
	}{
		{name: "missing creation command", kind: "missing command"},
		{name: "creation request digest drift", kind: "request digest"},
		{name: "creation outcome is not applied", kind: "not applied"},
		{name: "creation outcome digest drift", kind: "outcome digest"},
	} {
		t.Run(test.name, func(t *testing.T) {
			db, mock, token := newOwnedVerificationToken(t)
			defer db.Close()
			request := validSystemOwnerRequest()
			slot := validSystemActiveSlot(request)
			slotDigest := mustSystemSlotDigest(t, slot)
			command := validSystemCreateCommand(t, request, slot)

			expectSystemFenceAcquire(mock, 1)
			expectSystemCurrent(mock, slot, slotDigest, testSystemCreateCommand)
			expectSystemHistory(mock, systemHistory{
				commandID: testSystemCreateCommand,
				ordinal:   1,
				slot:      slot,
				digest:    slotDigest,
			})
			switch test.kind {
			case "missing command":
				expectSystemCommands(mock, request)
			case "request digest":
				command.requestDigest = systemOwnerDigest("f")
				expectSystemCommands(mock, request, command)
			case "not applied":
				expectSystemCommands(mock, request, command)
				expectSystemOutcome(
					mock,
					command,
					"EXPECTED_PRIOR_MISMATCH",
				)
			case "outcome digest":
				expectSystemCommands(mock, request, command)
				expectSystemOutcomeWithDigest(
					mock,
					command,
					"APPLIED",
					systemOwnerDigest("f"),
				)
			default:
				t.Fatalf("unknown test kind %q", test.kind)
			}

			if _, err := VerifySystemOwner(
				context.Background(),
				token,
				db,
				request,
			); !errors.Is(err, ErrSystemOwnerCorrupt) {
				t.Fatalf(
					"VerifySystemOwner error = %v, want ErrSystemOwnerCorrupt",
					err,
				)
			}

			mock.ExpectRollback()
			expectSystemFenceRelease(mock, 1)
			expectSystemSessionRestore(mock)
			if err := token.Close(); err != nil {
				t.Fatal(err)
			}
			assertVerificationExpectations(t, mock)
		})
	}
}

func TestVerifySystemOwnerMapsUnavailableFenceToConflictWithoutAuthorityRead(
	t *testing.T,
) {
	db, mock, token := newOwnedVerificationToken(t)
	defer db.Close()
	expectSystemFenceAcquire(mock, 0)

	if _, err := VerifySystemOwner(
		context.Background(),
		token,
		db,
		validSystemOwnerRequest(),
	); !errors.Is(err, ErrSystemOwnerConflict) {
		t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerConflict", err)
	}
	if !token.ActiveFor(db) {
		t.Fatal("unavailable system fence closed the source transaction")
	}

	mock.ExpectRollback()
	expectSystemSessionRestore(mock)
	if err := token.Close(); err != nil {
		t.Fatal(err)
	}
	assertVerificationExpectations(t, mock)
}

func validSystemOwnerRequest() SystemOwnerRequest {
	return SystemOwnerRequest{BundleKey: layoutbundlekeyv1.BundleKey{
		SlotOwnerKind:      layoutbundlekeyv1.SlotOwnerKindSystem,
		SlotOwnerNamespace: layoutbundlekeyv1.SystemSlotOwnerNamespace,
		LocalComponentKey: layoutbundlekeyv1.LocalComponentKey(
			"key256:" + strings.Repeat("7", 64),
		),
	}}
}

func validSystemActiveSlot(
	request SystemOwnerRequest,
) systemauthorityv1.SystemLayoutBundleSlotV1 {
	return systemauthorityv1.SystemLayoutBundleSlotV1{
		ValueVersion: systemauthorityv1.SlotValueVersion,
		BundleKey: systemauthorityv1.BundleKey{
			BundleKeyVersion:   layoutbundlekeyv1.BundleKeyVersion,
			SlotOwnerKind:      request.BundleKey.SlotOwnerKind,
			SlotOwnerNamespace: request.BundleKey.SlotOwnerNamespace,
			LocalComponentKey:  request.BundleKey.LocalComponentKey,
		},
		State: systemauthorityv1.SlotStateActive,
	}
}

func validSystemCreateCommand(
	t *testing.T,
	request SystemOwnerRequest,
	slot systemauthorityv1.SystemLayoutBundleSlotV1,
) systemCommand {
	t.Helper()
	commandRequest := systemauthorityv1.SystemLayoutBundleSlotCommandRequest{
		Operation:        systemauthorityv1.OperationCreate,
		TargetBundleKey:  slot.BundleKey,
		DesiredSlotValue: slot,
		ExpectedPrior: systemauthorityv1.ExpectedPrior{
			Variant: systemauthorityv1.ExpectedPriorAbsent,
		},
	}
	digest, err := systemauthorityv1.CommandRequestDigest(commandRequest)
	if err != nil {
		t.Fatal(err)
	}
	return systemCommand{
		commandID:     testSystemCreateCommand,
		principalID:   testSystemPrincipalID,
		auditDigest:   systemOwnerDigest("a"),
		request:       commandRequest,
		requestDigest: digest,
	}
}

func validSystemRetireCommand(
	t *testing.T,
	request SystemOwnerRequest,
	active systemauthorityv1.SystemLayoutBundleSlotV1,
	activeDigest string,
) systemCommand {
	t.Helper()
	tombstone := active
	tombstone.State = systemauthorityv1.SlotStateTombstone
	commandRequest := systemauthorityv1.SystemLayoutBundleSlotCommandRequest{
		Operation:        systemauthorityv1.OperationRetire,
		TargetBundleKey:  active.BundleKey,
		DesiredSlotValue: tombstone,
		ExpectedPrior: systemauthorityv1.ExpectedPrior{
			Variant:         systemauthorityv1.ExpectedPriorExact,
			SlotValueDigest: activeDigest,
		},
	}
	digest, err := systemauthorityv1.CommandRequestDigest(commandRequest)
	if err != nil {
		t.Fatal(err)
	}
	return systemCommand{
		commandID:     testSystemRetireCommand,
		principalID:   testSystemPrincipalID,
		auditDigest:   systemOwnerDigest("a"),
		request:       commandRequest,
		requestDigest: digest,
	}
}

func expectSystemCurrent(
	mock sqlmock.Sqlmock,
	slot systemauthorityv1.SystemLayoutBundleSlotV1,
	digest string,
	commandID systemauthorityv1.CommandID,
) {
	mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlot.*FOR UPDATE`).
		WithArgs(
			slot.BundleKey.BundleKeyVersion,
			string(slot.BundleKey.SlotOwnerKind),
			slot.BundleKey.SlotOwnerNamespace,
			string(slot.BundleKey.LocalComponentKey),
		).
		WillReturnRows(sqlmock.NewRows(systemCurrentColumns()).AddRow(
			slot.BundleKey.BundleKeyVersion,
			string(slot.BundleKey.SlotOwnerKind),
			[]byte(slot.BundleKey.SlotOwnerNamespace),
			[]byte(slot.BundleKey.LocalComponentKey),
			slot.ValueVersion,
			string(slot.State),
			digest,
			string(commandID),
		))
}

func expectSystemHistory(mock sqlmock.Sqlmock, history ...systemHistory) {
	rows := sqlmock.NewRows(systemHistoryColumns())
	for _, entry := range history {
		var prior any
		if entry.prior.Valid {
			prior = entry.prior.String
		}
		rows.AddRow(
			entry.slot.BundleKey.BundleKeyVersion,
			string(entry.slot.BundleKey.SlotOwnerKind),
			[]byte(entry.slot.BundleKey.SlotOwnerNamespace),
			[]byte(entry.slot.BundleKey.LocalComponentKey),
			[]byte(string(rune('0'+entry.ordinal))),
			string(entry.commandID),
			entry.slot.ValueVersion,
			string(entry.slot.State),
			entry.digest,
			prior,
		)
	}
	if len(history) == 0 {
		panic("expectSystemHistory requires at least one key source")
	}
	key := history[0].slot.BundleKey
	mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlotHistory.*ORDER BY TransitionOrdinal FOR UPDATE`).
		WithArgs(
			key.BundleKeyVersion,
			string(key.SlotOwnerKind),
			key.SlotOwnerNamespace,
			string(key.LocalComponentKey),
		).
		WillReturnRows(rows)
}

func expectSystemCommands(
	mock sqlmock.Sqlmock,
	request SystemOwnerRequest,
	commands ...systemCommand,
) {
	rows := sqlmock.NewRows(systemCommandColumns())
	for _, command := range commands {
		var prior any
		if command.request.ExpectedPrior.SlotValueDigest != "" {
			prior = command.request.ExpectedPrior.SlotValueDigest
		}
		rows.AddRow(
			string(command.commandID),
			[]byte(command.principalID),
			command.auditDigest,
			command.requestDigest,
			string(command.request.Operation),
			command.request.TargetBundleKey.BundleKeyVersion,
			string(command.request.TargetBundleKey.SlotOwnerKind),
			[]byte(command.request.TargetBundleKey.SlotOwnerNamespace),
			[]byte(command.request.TargetBundleKey.LocalComponentKey),
			command.request.DesiredSlotValue.ValueVersion,
			command.request.DesiredSlotValue.BundleKey.BundleKeyVersion,
			string(command.request.DesiredSlotValue.BundleKey.SlotOwnerKind),
			[]byte(command.request.DesiredSlotValue.BundleKey.SlotOwnerNamespace),
			[]byte(command.request.DesiredSlotValue.BundleKey.LocalComponentKey),
			string(command.request.DesiredSlotValue.State),
			string(command.request.ExpectedPrior.Variant),
			prior,
		)
	}
	mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlotCommand.*ORDER BY CommandId FOR UPDATE`).
		WithArgs(systemKeyArgs(request)...).
		WillReturnRows(rows)
}

func expectSystemOutcome(
	mock sqlmock.Sqlmock,
	command systemCommand,
	result string,
) {
	outcome := systemOutcome{
		commandID:     command.commandID,
		requestDigest: command.requestDigest,
		principalID:   command.principalID,
		auditDigest:   command.auditDigest,
		result:        result,
	}
	digest, err := systemOutcomeDigest(outcome)
	if err != nil {
		panic(err)
	}
	expectSystemOutcomeWithDigest(mock, command, result, digest)
}

func expectSystemOutcomeWithDigest(
	mock sqlmock.Sqlmock,
	command systemCommand,
	result string,
	digest string,
) {
	mock.ExpectQuery(`(?s)FROM _System_CatalogSystemLayoutBundleSlotCommandOutcome.*FOR UPDATE`).
		WithArgs(string(command.commandID)).
		WillReturnRows(sqlmock.NewRows(systemOutcomeColumns()).AddRow(
			string(command.commandID),
			command.requestDigest,
			[]byte(command.principalID),
			command.auditDigest,
			result,
			digest,
		))
}

func mustSystemSlotDigest(
	t *testing.T,
	slot systemauthorityv1.SystemLayoutBundleSlotV1,
) string {
	t.Helper()
	digest, err := systemauthorityv1.SlotValueDigest(slot)
	if err != nil {
		t.Fatal(err)
	}
	return digest
}

func systemKeyArgs(request SystemOwnerRequest) []driver.Value {
	return []driver.Value{
		layoutbundlekeyv1.BundleKeyVersion,
		string(request.BundleKey.SlotOwnerKind),
		request.BundleKey.SlotOwnerNamespace,
		string(request.BundleKey.LocalComponentKey),
	}
}

func systemCurrentColumns() []string {
	return []string{
		"BundleKeyVersion",
		"SlotOwnerKind",
		"SlotOwnerNamespace",
		"LocalComponentKey",
		"ValueVersion",
		"State",
		"ValueDigest",
		"LastCommandId",
	}
}

func systemHistoryColumns() []string {
	return []string{
		"BundleKeyVersion",
		"SlotOwnerKind",
		"SlotOwnerNamespace",
		"LocalComponentKey",
		"TransitionOrdinal",
		"CommandId",
		"ValueVersion",
		"State",
		"ValueDigest",
		"PriorValueDigest",
	}
}

func systemCommandColumns() []string {
	return []string{
		"CommandId",
		"PrincipalId",
		"PrincipalAuditDigest",
		"RequestDigest",
		"Operation",
		"TargetBundleKeyVersion",
		"TargetSlotOwnerKind",
		"TargetSlotOwnerNamespace",
		"TargetLocalComponentKey",
		"DesiredValueVersion",
		"DesiredBundleKeyVersion",
		"DesiredSlotOwnerKind",
		"DesiredSlotOwnerNamespace",
		"DesiredLocalComponentKey",
		"DesiredState",
		"ExpectedPriorVariant",
		"ExpectedPriorDigest",
	}
}

func systemOutcomeColumns() []string {
	return []string{
		"CommandId",
		"RequestDigest",
		"PrincipalId",
		"PrincipalAuditDigest",
		"Result",
		"OutcomeDigest",
	}
}

func systemOwnerDigest(character string) string {
	return "sha256:" + strings.Repeat(character, 64)
}

func TestValidateSystemOwnerRequestRejectsNonSystemKey(t *testing.T) {
	request := validSystemOwnerRequest()
	request.BundleKey.SlotOwnerKind = layoutbundlekeyv1.SlotOwnerKindTenant
	if _, err := VerifySystemOwner(
		context.Background(),
		nil,
		nil,
		request,
	); !errors.Is(err, ErrSystemOwnerConflict) {
		t.Fatalf("VerifySystemOwner error = %v, want ErrSystemOwnerConflict", err)
	}
}

func TestSystemOutcomeDigestRejectsChangedBinding(t *testing.T) {
	request := validSystemOwnerRequest()
	slot := validSystemActiveSlot(request)
	command := validSystemCreateCommand(t, request, slot)
	outcome := systemOutcome{
		commandID:     command.commandID,
		requestDigest: command.requestDigest,
		principalID:   command.principalID,
		auditDigest:   command.auditDigest,
		result:        "APPLIED",
	}
	digest, err := systemOutcomeDigest(outcome)
	if err != nil {
		t.Fatal(err)
	}
	outcome.outcomeDigest = digest
	if err := validateSystemOutcome(outcome, command); err != nil {
		t.Fatal(err)
	}
	changed := outcome
	changed.result = "EXPECTED_PRIOR_MISMATCH"
	if err := validateSystemOutcome(changed, command); !errors.Is(
		err,
		ErrSystemOwnerCorrupt,
	) {
		t.Fatalf("changed outcome validation = %v", err)
	}
}
