package mongo

import (
	"fmt"

	"go.mongodb.org/mongo-driver/v2/bson"
)

const (
	// DefaultListLimit is the default page size for admin list endpoints.
	DefaultListLimit = 10
	// MaxListLimit is the maximum allowed page size.
	MaxListLimit = 100
)

// ListPaginationOptions configures optional list pagination behavior.
type ListPaginationOptions struct {
	Projection bson.M
}

// BuildListPagination converts API pagination parameters into MongoDB pagination options.
// filter is used to bind cursors to the active query filters via a hash.
func BuildListPagination(
	limit, offset int,
	cursor, sortField, sortOrder string,
	filter bson.M,
	opts ListPaginationOptions,
) (Pagination, error) {
	if limit <= 0 {
		limit = DefaultListLimit
	}
	if limit > MaxListLimit {
		return Pagination{}, fmt.Errorf("%w: limit must be between 1 and %d", ErrInvalidPagination, MaxListLimit)
	}

	if sortField == "" {
		sortField = "created_at"
	}
	if sortOrder == "" {
		sortOrder = "desc"
	}

	sortOrderInt := -1
	if sortOrder == "asc" {
		sortOrderInt = 1
	}

	filtersHash := HashFilter(filter)

	pb := NewPaginationBuilder().
		Limit(limit).
		SortBy(sortField, sortOrder)

	if len(opts.Projection) > 0 {
		pb.Projection(opts.Projection)
	}

	if cursor != "" {
		pageCursor, err := decodePageCursor(cursor)
		if err != nil {
			return Pagination{}, err
		}
		if !pageCursor.matches(sortField, sortOrderInt) {
			return Pagination{}, fmt.Errorf("%w: cursor does not match requested sort", ErrInvalidCursor)
		}
		if pageCursor.FiltersHash != filtersHash {
			return Pagination{}, fmt.Errorf("%w: cursor does not match current filters", ErrInvalidCursor)
		}
		pb.Cursor(cursor)
	} else {
		if offset < 0 {
			return Pagination{}, fmt.Errorf("%w: offset cannot be negative", ErrInvalidPagination)
		}
		pb.Skip(offset)
	}

	return pb.Build(), nil
}
