{{ define "header" }}{{- /*gotype: go.mau.fi/mautrix-telegram/pkg/gotd/telegram/query/internal/itergen.Config*/ -}}
// Code generated by itergen, DO NOT EDIT.

package {{ $.Package }}

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 {
{{- range $arg := $.RequestFields }}
    {{ $arg.OriginalName }} {{ $arg.Type }}
{{- end }}
    Limit int
}

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

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

// Query implements Query interface.
func (q QueryFunc) Query(ctx context.Context, req Request) (tg.{{ $.ResultName }}, 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}
}

{{ range $method := $.Methods }}
{{ template "query" $method }}
{{- end }}
{{ end }}

{{ define "query" }}{{- /*gotype: go.mau.fi/mautrix-telegram/pkg/gotd/telegram/query/internal/gen.Method*/ -}}
// {{ $.Name }}QueryBuilder is query builder of {{ $.OriginalName }}.
type {{ $.Name }}QueryBuilder struct {
    raw *tg.Client
    req {{ $.RequestName }}
    batchSize int
    {{- range $mapping := $.AdditionalMapping }}
    {{ $mapping.Arg.Name }} {{ $mapping.Arg.Type }}
    {{- end }}
}

// {{ $.Name }} creates query builder of {{ $.OriginalName }}.
func (q *QueryBuilder) {{ $.Name }}({{ range $arg := $.RequiredParams }}param{{ $arg.OriginalName }} {{ $arg.Type }},{{ end }}) *{{ $.Name }}QueryBuilder {
    b := &{{ $.Name }}QueryBuilder{
        raw: q.raw,
        batchSize: 1,
        req:{{ $.RequestName }}{
        {{- range $f := $.AdditionalParams }}{{ if eq ($f.Type) ("tg.MessagesFilterClass") }}
            {{ $f.OriginalName }}: &tg.InputMessagesFilterEmpty{},
        {{- end }}{{ if eq ($f.Type) ("tg.InputPeerClass") }}
            {{ $f.OriginalName }}: &tg.InputPeerEmpty{},
        {{- end }}{{ if eq ($f.Type) ("tg.ChannelParticipantsFilterClass") }}
            {{ $f.OriginalName }}: &tg.ChannelParticipantsRecent{},
        {{- end }}{{ end }}
        },
    }
{{ range $arg := $.RequiredParams }}
   b.req.{{ $arg.OriginalName }} = param{{ $arg.OriginalName }}
{{- end }}
    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 *{{ $.Name }}QueryBuilder) BatchSize(batchSize int) *{{ $.Name }}QueryBuilder {
    b.batchSize = batchSize
    return b
}

{{- range $mapping := $.AdditionalMapping }}{{ if $mapping.Chain }}
// {{ $mapping.Arg.OriginalName }} sets {{ $mapping.Arg.Name }} from which iterate start.
func (b *{{ $.Name }}QueryBuilder) {{ $mapping.Arg.OriginalName }}({{ $mapping.Arg.Name }} int) *{{ $.Name }}QueryBuilder {
    b.{{ $mapping.Arg.Name }} = {{ $mapping.Arg.Name }}
    return b
}
{{- end }}{{- end }}

{{ range $f := $.AdditionalParams }}
// {{ $f.MethodName }} sets {{ $f.OriginalName }} field of {{ $.Name }} query.
func (b *{{ $.Name }}QueryBuilder) {{ $f.MethodName }}(param{{ $f.OriginalName }} {{ $f.Type }}) *{{ $.Name }}QueryBuilder {    b.req.{{ $f.OriginalName }} = param{{ $f.OriginalName }}
    return b
}
{{ end }}

{{ range $f := $.SpecialCase }}
// {{ $f.ConstructorName }} sets {{ $f.Field.OriginalName }} field of {{ $.Name }} query.
func (b *{{ $.Name }}QueryBuilder) {{ $f.ConstructorName }}({{ range $arg := $f.Args }}param{{ $arg.OriginalName }} {{ $arg.Type }},{{ end }}) *{{ $.Name }}QueryBuilder {
    b.req.{{ $f.Field.OriginalName }} = &{{ $f.ConstructorType }}{
    {{- range $arg := $f.Args }}
        {{ $arg.OriginalName }}: param{{ $arg.OriginalName }},
    {{- end }}
    }
    return b
}
{{ end }}


// Query implements Query interface.
func (b *{{ $.Name }}QueryBuilder) Query(ctx context.Context, req Request) ({{ $.ResultName }}, error) {
	r := &{{ $.RequestName }}{
		Limit:     req.Limit,
	}
    {{ range $f := $.AdditionalParams }}
    r.{{ $f.OriginalName }} = b.req.{{ $f.OriginalName }}
    {{- end }}
	{{- range $f := $.AdditionalMapping }}
    r.{{ $f.Arg.OriginalName }} = req.{{ $f.Arg.OriginalName }}
    {{- end }}
	return b.raw.{{ $.OriginalName }}(ctx, r)
}

// Iter returns iterator using built query.
func (b *{{ $.Name }}QueryBuilder) Iter() *{{ $.IteratorName }} {
	iter := New{{ $.IteratorName }}(b, b.batchSize)
{{- range $mapping := $.AdditionalMapping }}{{ if $mapping.RequiredByIter }}
    iter = iter.{{ $mapping.Arg.OriginalName }}(b.{{ $mapping.Arg.Name }})
{{- end }}{{- end }}
    return iter
}

// ForEach calls given callback on each iterator element.
func (b *{{ $.Name }}QueryBuilder) ForEach(ctx context.Context, cb func(context.Context, {{ $.ElemName }}) 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 *{{ $.Name }}QueryBuilder) 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 *{{ $.Name }}QueryBuilder) Collect(ctx context.Context) ([]{{ $.ElemName }}, error) {
    iter := b.Iter()
    c, err := iter.Total(ctx)
    if err != nil {
        return nil, errors.Wrap(err, "get total")
    }

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

    return r, iter.Err()
}
{{ end }}
