// Code generated by itergen, DO NOT EDIT.

package participants

import (
	"context"

	"github.com/go-faster/errors"

	"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)

// No-op definition for keeping imports.
var _ = context.Background()

// Request is a parameter for Query.
type Request struct {
	Offset int
	Limit  int
}

// Query is an abstraction for participants request.
// NB: iterator mutates returned data (sorts, at least).
type Query interface {
	Query(ctx context.Context, req Request) (tg.ChannelsChannelParticipantsClass, error)
}

// QueryFunc is a function adapter for Query.
type QueryFunc func(ctx context.Context, req Request) (tg.ChannelsChannelParticipantsClass, error)

// Query implements Query interface.
func (q QueryFunc) Query(ctx context.Context, req Request) (tg.ChannelsChannelParticipantsClass, error) {
	return q(ctx, req)
}

// QueryBuilder is a helper to create message queries.
type QueryBuilder struct {
	raw *tg.Client
}

// NewQueryBuilder creates new QueryBuilder.
func NewQueryBuilder(raw *tg.Client) *QueryBuilder {
	return &QueryBuilder{raw: raw}
}

// GetParticipantsQueryBuilder is query builder of ChannelsGetParticipants.
type GetParticipantsQueryBuilder struct {
	raw       *tg.Client
	req       tg.ChannelsGetParticipantsRequest
	batchSize int
	offset    int
}

// GetParticipants creates query builder of ChannelsGetParticipants.
func (q *QueryBuilder) GetParticipants(paramChannel tg.InputChannelClass) *GetParticipantsQueryBuilder {
	b := &GetParticipantsQueryBuilder{
		raw:       q.raw,
		batchSize: 1,
		req: tg.ChannelsGetParticipantsRequest{
			Filter: &tg.ChannelParticipantsRecent{},
		},
	}

	b.req.Channel = paramChannel
	return b
}

// BatchSize sets buffer of message loaded from one request.
// Be carefully, when set this limit, because Telegram does not return error if limit is too big,
// so results can be incorrect.
func (b *GetParticipantsQueryBuilder) BatchSize(batchSize int) *GetParticipantsQueryBuilder {
	b.batchSize = batchSize
	return b
}

// Channel sets Channel field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Channel(paramChannel tg.InputChannelClass) *GetParticipantsQueryBuilder {
	b.req.Channel = paramChannel
	return b
}

// Filter sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Filter(paramFilter tg.ChannelParticipantsFilterClass) *GetParticipantsQueryBuilder {
	b.req.Filter = paramFilter
	return b
}

// Admins sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Admins() *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsAdmins{}
	return b
}

// Banned sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Banned(paramQ string) *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsBanned{
		Q: paramQ,
	}
	return b
}

// Bots sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Bots() *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsBots{}
	return b
}

// Contacts sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Contacts(paramQ string) *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsContacts{
		Q: paramQ,
	}
	return b
}

// Kicked sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Kicked(paramQ string) *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsKicked{
		Q: paramQ,
	}
	return b
}

// Mentions sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Mentions(paramQ string, paramTopMsgID int) *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsMentions{
		Q:        paramQ,
		TopMsgID: paramTopMsgID,
	}
	return b
}

// Recent sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Recent() *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsRecent{}
	return b
}

// Search sets Filter field of GetParticipants query.
func (b *GetParticipantsQueryBuilder) Search(paramQ string) *GetParticipantsQueryBuilder {
	b.req.Filter = &tg.ChannelParticipantsSearch{
		Q: paramQ,
	}
	return b
}

// Query implements Query interface.
func (b *GetParticipantsQueryBuilder) Query(ctx context.Context, req Request) (tg.ChannelsChannelParticipantsClass, error) {
	r := &tg.ChannelsGetParticipantsRequest{
		Limit: req.Limit,
	}

	r.Channel = b.req.Channel
	r.Filter = b.req.Filter
	r.Offset = req.Offset
	return b.raw.ChannelsGetParticipants(ctx, r)
}

// Iter returns iterator using built query.
func (b *GetParticipantsQueryBuilder) Iter() *Iterator {
	iter := NewIterator(b, b.batchSize)
	iter = iter.Offset(b.offset)
	return iter
}

// ForEach calls given callback on each iterator element.
func (b *GetParticipantsQueryBuilder) ForEach(ctx context.Context, cb func(context.Context, Elem) error) error {
	iter := b.Iter()
	for iter.Next(ctx) {
		if err := cb(ctx, iter.Value()); err != nil {
			return err
		}
	}
	return iter.Err()
}

// Count fetches remote state to get number of elements.
func (b *GetParticipantsQueryBuilder) Count(ctx context.Context) (int, error) {
	iter := b.Iter()
	c, err := iter.Total(ctx)
	if err != nil {
		return 0, errors.Wrap(err, "get total")
	}
	return c, nil
}

// Collect creates iterator and collects all elements to slice.
func (b *GetParticipantsQueryBuilder) Collect(ctx context.Context) ([]Elem, error) {
	iter := b.Iter()
	c, err := iter.Total(ctx)
	if err != nil {
		return nil, errors.Wrap(err, "get total")
	}

	r := make([]Elem, 0, c)
	for iter.Next(ctx) {
		r = append(r, iter.Value())
	}

	return r, iter.Err()
}
