package database

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
)

// --- Unit tests for Paginate parameter clamping ---

func TestPaginate_PageZeroDefaultsToOne(t *testing.T) {
	scope := Paginate(0, 10)

	db := openTestDB(t)
	createTestRows(t, db, 5)

	var rows []testRow
	err := db.Scopes(scope).Find(&rows).Error
	require.NoError(t, err)
	// page=0 normalised to page=1, pageSize=10 → should get all 5 rows
	assert.Len(t, rows, 5)
}

func TestPaginate_PageSizeZeroDefaultsTo100(t *testing.T) {
	scope := Paginate(1, 0)

	db := openTestDB(t)
	createTestRows(t, db, 5)

	var rows []testRow
	err := db.Scopes(scope).Find(&rows).Error
	require.NoError(t, err)
	// pageSize=0 normalised to 100, only 5 rows exist → 5 returned
	assert.Len(t, rows, 5)
}

func TestPaginate_PageSizeOverMaxCappedAt1000(t *testing.T) {
	scope := Paginate(1, 2000)

	db := openTestDB(t)
	createTestRows(t, db, 5)

	var rows []testRow
	err := db.Scopes(scope).Find(&rows).Error
	require.NoError(t, err)
	// pageSize=2000 capped to 1000, only 5 rows → 5 returned
	assert.Len(t, rows, 5)
}

func TestPaginate_NormalValues(t *testing.T) {
	scope := Paginate(1, 3)

	db := openTestDB(t)
	createTestRows(t, db, 10)

	var rows []testRow
	err := db.Scopes(scope).Order("id ASC").Find(&rows).Error
	require.NoError(t, err)
	assert.Len(t, rows, 3)
	assert.Equal(t, "row_1", rows[0].Name)
	assert.Equal(t, "row_3", rows[2].Name)
}

func TestPaginate_SQLiteIntegration_Page2Size10(t *testing.T) {
	db := openTestDB(t)
	createTestRows(t, db, 25)

	scope := Paginate(2, 10)
	var rows []testRow
	err := db.Scopes(scope).Order("id ASC").Find(&rows).Error
	require.NoError(t, err)

	// Page 2 with size 10 → rows 11..20
	assert.Len(t, rows, 10)
	assert.Equal(t, "row_11", rows[0].Name)
	assert.Equal(t, "row_20", rows[9].Name)
}

// --- helpers ---

type testRow struct {
	ID   uint   `gorm:"primaryKey"`
	Name string
}

func openTestDB(t *testing.T) *gorm.DB {
	t.Helper()
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&testRow{}))
	return db
}

func createTestRows(t *testing.T, db *gorm.DB, n int) {
	t.Helper()
	for i := 1; i <= n; i++ {
		require.NoError(t, db.Create(&testRow{Name: fmt.Sprintf("row_%d", i)}).Error)
	}
}
