package utils

import (
	"testing"
)

func TestNewPagination(t *testing.T) {
	tests := []struct {
		name      string
		page      int
		limit     int
		totalRows int64
		wantErr   bool
		wantPage  int
		wantLimit int
	}{
		{
			name:      "valid pagination",
			page:      2,
			limit:     10,
			totalRows: 100,
			wantErr:   false,
			wantPage:  2,
			wantLimit: 10,
		},
		{
			name:      "invalid page - corrected to 1",
			page:      0,
			limit:     10,
			totalRows: 100,
			wantErr:   false,
			wantPage:  1,
			wantLimit: 10,
		},
		{
			name:      "invalid limit - corrected to default",
			page:      1,
			limit:     0,
			totalRows: 100,
			wantErr:   false,
			wantPage:  1,
			wantLimit: 10, // default
		},
		{
			name:      "limit too high - corrected to max",
			page:      1,
			limit:     200,
			totalRows: 100,
			wantErr:   false,
			wantPage:  1,
			wantLimit: 100, // max
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p, err := NewPagination(tt.page, tt.limit, tt.totalRows)

			if (err != nil) != tt.wantErr {
				t.Errorf("NewPagination() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if err == nil {
				if p.Page != tt.wantPage {
					t.Errorf("NewPagination() page = %v, want %v", p.Page, tt.wantPage)
				}
				if p.Limit != tt.wantLimit {
					t.Errorf("NewPagination() limit = %v, want %v", p.Limit, tt.wantLimit)
				}
			}
		})
	}
}

func TestPaginationMetadata(t *testing.T) {
	p, err := NewPagination(2, 10, 25)
	if err != nil {
		t.Fatalf("NewPagination() error = %v", err)
	}

	// Test total pages calculation
	if p.TotalPages != 3 {
		t.Errorf("TotalPages = %v, want 3", p.TotalPages)
	}

	// Test HasNext/HasPrev
	if !p.HasNext {
		t.Error("HasNext should be true for page 2 of 3")
	}
	if !p.HasPrev {
		t.Error("HasPrev should be true for page 2")
	}

	// Test NextPage/PrevPage
	if p.NextPage == nil || *p.NextPage != 3 {
		t.Errorf("NextPage = %v, want 3", p.NextPage)
	}
	if p.PrevPage == nil || *p.PrevPage != 1 {
		t.Errorf("PrevPage = %v, want 1", p.PrevPage)
	}
}

func TestPaginationHelpers(t *testing.T) {
	p, _ := NewPagination(2, 10, 25)

	// Test GetOffset
	if offset := p.GetOffset(); offset != 10 {
		t.Errorf("GetOffset() = %v, want 10", offset)
	}

	// Test GetStartIndex
	if start := p.GetStartIndex(); start != 11 {
		t.Errorf("GetStartIndex() = %v, want 11", start)
	}

	// Test GetEndIndex
	if end := p.GetEndIndex(); end != 20 {
		t.Errorf("GetEndIndex() = %v, want 20", end)
	}

	// Test IsFirstPage
	if p.IsFirstPage() {
		t.Error("IsFirstPage() should be false for page 2")
	}

	// Test IsLastPage
	if p.IsLastPage() {
		t.Error("IsLastPage() should be false for page 2 of 3")
	}

	// Test IsEmpty
	if p.IsEmpty() {
		t.Error("IsEmpty() should be false when TotalRows > 0")
	}
}

func TestPaginationPageRange(t *testing.T) {
	tests := []struct {
		name      string
		page      int
		totalRows int64
		maxPages  int
		expected  []int
	}{
		{
			name:      "small total pages",
			page:      2,
			totalRows: 30, // 3 total pages
			maxPages:  5,
			expected:  []int{1, 2, 3},
		},
		{
			name:      "middle page",
			page:      5,
			totalRows: 100, // 10 total pages
			maxPages:  5,
			expected:  []int{3, 4, 5, 6, 7},
		},
		{
			name:      "near end",
			page:      9,
			totalRows: 100, // 10 total pages
			maxPages:  5,
			expected:  []int{6, 7, 8, 9, 10},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p, _ := NewPagination(tt.page, 10, tt.totalRows)
			result := p.GetPageRange(tt.maxPages)

			if len(result) != len(tt.expected) {
				t.Errorf("GetPageRange() length = %v, want %v", len(result), len(tt.expected))
				return
			}

			for i, page := range result {
				if page != tt.expected[i] {
					t.Errorf("GetPageRange()[%d] = %v, want %v", i, page, tt.expected[i])
				}
			}
		})
	}
}

func TestPaginationClone(t *testing.T) {
	original, _ := NewPagination(2, 10, 100)
	clone, err := original.Clone(3, 20)

	if err != nil {
		t.Fatalf("Clone() error = %v", err)
	}

	if clone.Page != 3 {
		t.Errorf("Clone() page = %v, want 3", clone.Page)
	}
	if clone.Limit != 20 {
		t.Errorf("Clone() limit = %v, want 20", clone.Limit)
	}
	if clone.TotalRows != original.TotalRows {
		t.Errorf("Clone() totalRows = %v, want %v", clone.TotalRows, original.TotalRows)
	}
}

func BenchmarkNewPagination(b *testing.B) {
	for i := 0; i < b.N; i++ {
		NewPagination(1, 10, 1000)
	}
}

func BenchmarkGetPageRange(b *testing.B) {
	p, _ := NewPagination(50, 10, 10000)

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		p.GetPageRange(10)
	}
}
