//go:build test
// +build test

package testutils

import (
	"context"
	"testing"

	"crussell/db"
)

// txSemaphore limits concurrent test transactions per package to prevent
// pgxpool connection exhaustion when many tests use t.Parallel().
// The cap (8) should match the -parallel N flag used in test invocations
// and should be well below MaxConns per pool (currently 16).
var txSemaphore = make(chan struct{}, 8)

// SetupTestTx begins a transaction on the db.Conn pool, stores it in the
// returned context (for PoolProxy routing), and returns the raw tx for use
// with fixture functions (e.g. fixtures.CreateTestUser(tx)).
//
// The transaction is automatically rolled back in t.Cleanup. After calling
// SetupTestTx, the test should call t.Parallel() and pass the returned context
// to any request helper functions (MakeRequest, makeAdminRequest, etc.).
//
// Example:
//
//	func TestMyHandler(t *testing.T) {
//	    t.Parallel()
//	    ctx, tx := testutils.SetupTestTx(t)
//	    userID, _ := fixtures.CreateTestUser(tx)
//	    w := testutils.MakeUserRequest(handler, "GET", "/api/foo", nil, userID, ctx)
//	    assert.Equal(t, 200, w.Code)
//	}
func SetupTestTx(t *testing.T) (context.Context, db.Querier) {
	t.Helper()
	txSemaphore <- struct{}{}
	pool := db.Conn.Pool()
	tx, err := pool.Begin(context.Background())
	if err != nil {
		<-txSemaphore
		t.Fatalf("SetupTestTx: failed to begin transaction: %v", err)
	}
	ctx := db.ContextWithTx(context.Background(), tx)
	t.Cleanup(func() {
		tx.Rollback(context.Background())
		<-txSemaphore
	})
	return ctx, tx
}

