package types

import (
	"fmt"
)

// KVStorePrefixIteratorPaginated returns iterator over items in the selected page.
// Items iterated and skipped in ascending order.
func KVStorePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator {
	pi := &PaginatedIterator{
		Iterator: KVStorePrefixIterator(kvs, prefix),
		page:     page,
		limit:    limit,
	}
	pi.skip()
	return pi
}

// KVStoreReversePrefixIteratorPaginated returns iterator over items in the selected page.
// Items iterated and skipped in descending order.
func KVStoreReversePrefixIteratorPaginated(kvs KVStore, prefix []byte, page, limit uint) Iterator {
	pi := &PaginatedIterator{
		Iterator: KVStoreReversePrefixIterator(kvs, prefix),
		page:     page,
		limit:    limit,
	}
	pi.skip()
	return pi
}

// PaginatedIterator is a wrapper around Iterator that iterates over values starting for given page and limit.
type PaginatedIterator struct {
	Iterator

	page, limit uint // provided during initialization
	iterated    uint // incremented in a call to Next

}

func (pi *PaginatedIterator) skip() {
	for i := (pi.page - 1) * pi.limit; i > 0 && pi.Iterator.Valid(); i-- {
		pi.Iterator.Next()
	}
}

// Next will panic after limit is reached.
func (pi *PaginatedIterator) Next() {
	if !pi.Valid() {
		panic(fmt.Sprintf("PaginatedIterator reached limit %d", pi.limit))
	}
	pi.Iterator.Next()
	pi.iterated++
}

// Valid if below limit and underlying iterator is valid.
func (pi *PaginatedIterator) Valid() bool {
	if pi.iterated >= pi.limit {
		return false
	}
	return pi.Iterator.Valid()
}
