package automation

import (
	"context"
	"slices"
	"testing"

	"github.com/nexuscrm/kernel/pkg/logging"
	"github.com/nexuscrm/kernel/pkg/recordlocks"
)

type approvalForcedParentPrelockPersistence struct {
	*t8PersistenceAdapter
	lockedByAttempt map[int][]recordlocks.ParentKey
}

func newApprovalForcedParentPrelockPersistence() *approvalForcedParentPrelockPersistence {
	return &approvalForcedParentPrelockPersistence{
		t8PersistenceAdapter: newT8PersistenceAdapter(),
		lockedByAttempt:      map[int][]recordlocks.ParentKey{},
	}
}

func (p *approvalForcedParentPrelockPersistence) LockParentRows(_ context.Context, keys []recordlocks.ParentKey) ([]recordlocks.ParentKey, error) {
	ordered := recordlocks.OrderedParentKeys(keys)
	p.lockedByAttempt[p.stub.attempt] = append([]recordlocks.ParentKey(nil), ordered...)
	return ordered, nil
}

func TestApprovalSubmitRetriesWithDiscoveredParentInInitialLockSet(t *testing.T) {
	persistence := newApprovalForcedParentPrelockPersistence()
	service := NewApprovalService(persistence, nil, nil, nil, nil, nil, nil, logging.Default)
	discovered := recordlocks.ParentKey{ObjectName: "Account", RecordID: "account-001"}

	err := persistence.RunInPessimisticTransaction(t.Context(), func(txCtx context.Context) error {
		if err := service.prelockSubmitRuntimeParents(
			txCtx,
			"WorkItem",
			"workitem-001",
			"process-definition-001",
			"process-node-001",
			[]string{"approver-001"},
			"submitter-001",
			true,
		); err != nil {
			return err
		}
		if !slices.Contains(persistence.lockedByAttempt[persistence.stub.attempt], discovered) {
			return &outOfOrderRetryErrForT8{keys: []recordlocks.ParentKey{discovered}}
		}
		return nil
	})
	if err != nil {
		t.Fatalf("approval submit did not converge after parent-lock retry: %v", err)
	}
	if persistence.txm.pessimisticCalls != 2 {
		t.Fatalf("pessimistic attempts = %d, want 2", persistence.txm.pessimisticCalls)
	}
	if !slices.Contains(persistence.lockedByAttempt[2], discovered) {
		t.Fatalf("second attempt initial parent locks = %#v, want discovered parent %#v", persistence.lockedByAttempt[2], discovered)
	}
}
