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

package {{ $.Package }}

import (
    "context"
    "sync/atomic"

    "github.com/go-faster/errors"

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

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

{{ range $query := $.Queries }}

type inner{{ $query.Name }} struct {
    // Last received hash.
    hash  int64
    // Last received result.
	value *tg.{{ $query.ResultName }}
}

type {{ $query.Name }} struct {
    {{- if $query.RequestParams }}
    // Query to send.
    req *tg.{{ $query.RequestName }}{{ end }}
    // Result state.
    last atomic.Value

    // Reference to RPC client to make requests.
	  raw *tg.Client
}

// New{{ $query.Name }} creates new {{ $query.Name }}.
func New{{ $query.Name }}(raw *tg.Client, {{- if $query.RequestParams }}initial *tg.{{ $query.RequestName }}{{- end }}) *{{ $query.Name }} {
    q := &{{ $query.Name }}{
        {{- if $query.RequestParams }}
        req: initial,{{ end }}
        raw: raw,
    }

    return q
}

func (s *{{ $query.Name }}) store(v inner{{ $query.Name }}) {
    s.last.Store(v)
}

func (s *{{ $query.Name }}) load() (inner{{ $query.Name }}, bool) {
    v, ok := s.last.Load().(inner{{ $query.Name }})
    return v, ok
}

// Value returns last received result.
// NB: May be nil. Returned {{ $query.ResultName }} must not be mutated.
func (s *{{ $query.Name }}) Value() *tg.{{ $query.ResultName }} {
	inner, _ := s.load()
	return inner.value
}

// Hash returns last received hash.
func (s *{{ $query.Name }}) Hash() int64 {
    inner, _ := s.load()
    return inner.hash
}

// Get updates data if needed and returns it.
func (s *{{ $query.Name }}) Get(ctx context.Context) (*tg.{{ $query.ResultName }}, error) {
    if _, err := s.Fetch(ctx); err != nil {
        return nil, err
    }

    return s.Value(), nil
}

// Fetch updates data if needed and returns true if data was modified.
func (s *{{ $query.Name }}) Fetch(ctx context.Context) (bool, error) {
    lastHash := s.Hash()

    {{ if $query.RequestParams -}}
    req := s.req
    req.Hash = lastHash
    {{- else -}}
    req := lastHash
    {{- end }}
	result, err := s.raw.{{ $query.MethodName }}(ctx, req)
	if err != nil {
		return false, errors.Wrap(err, "execute {{ $query.MethodName }}")
	}

	switch variant := result.(type) {
    case *tg.{{ $query.ResultName }}:
        {{ if $query.ManualHash -}}
        hash := s.computeHash(variant)
        {{- else -}}
        hash := variant.Hash
        {{- end }}

        s.store(inner{{ $query.Name }}{
            hash: hash,
            value: variant,
        })
        return true, nil
	case *tg.{{ $query.NotModifiedName }}:
		if lastHash == 0 {
			return false, errors.Errorf("got unexpected %T result", result)
		}
        return false, nil
	default:
		return false, errors.Errorf("unexpected type %T", result)
	}
}
{{ end }}

{{ end }}
