// Code generated by gotdgen, DO NOT EDIT.

package tg

import (
	"context"
	"errors"
	"fmt"
	"sort"
	"strings"

	"go.uber.org/multierr"

	"go.mau.fi/mautrix-telegram/pkg/gotd/bin"
	"go.mau.fi/mautrix-telegram/pkg/gotd/tdjson"
	"go.mau.fi/mautrix-telegram/pkg/gotd/tdp"
	"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
)

// No-op definition for keeping imports.
var (
	_ = bin.Buffer{}
	_ = context.Background()
	_ = fmt.Stringer(nil)
	_ = strings.Builder{}
	_ = errors.Is
	_ = multierr.AppendInto
	_ = sort.Ints
	_ = tdp.Format
	_ = tgerr.Error{}
	_ = tdjson.Encoder{}
)

// Poll represents TL type `poll#966e2dbf`.
// Poll
//
// See https://core.telegram.org/constructor/poll for reference.
type Poll struct {
	// ID of the poll
	ID int64
	// Flags, see TL conditional fields¹
	//
	// Links:
	//  1) https://core.telegram.org/mtproto/TL-combinators#conditional-fields
	Flags bin.Fields
	// Whether the poll is closed and doesn't accept any more answers
	Closed bool
	// Whether cast votes are publicly visible to all users (non-anonymous poll)
	PublicVoters bool
	// Whether multiple options can be chosen as answer
	MultipleChoice bool
	// Whether this is a quiz (with wrong and correct answers, results shown in the return
	// type)
	Quiz bool
	// OpenAnswers field of Poll.
	OpenAnswers bool
	// RevotingDisabled field of Poll.
	RevotingDisabled bool
	// ShuffleAnswers field of Poll.
	ShuffleAnswers bool
	// HideResultsUntilClose field of Poll.
	HideResultsUntilClose bool
	// Creator field of Poll.
	Creator bool
	// SubscribersOnly field of Poll.
	SubscribersOnly bool
	// The question of the poll (only Premium¹ users can use custom emoji entities² here).
	//
	// Links:
	//  1) https://core.telegram.org/api/premium
	//  2) https://core.telegram.org/api/custom-emoji
	Question TextWithEntities
	// The possible answers (2-poll_answers_max¹), vote using messages.sendVote².
	//
	// Links:
	//  1) https://core.telegram.org/api/config#poll-answers-max
	//  2) https://core.telegram.org/method/messages.sendVote
	Answers []PollAnswerClass
	// Amount of time in seconds the poll will be active after creation, 5-600. Can't be used
	// together with close_date.
	//
	// Use SetClosePeriod and GetClosePeriod helpers.
	ClosePeriod int
	// Point in time (Unix timestamp) when the poll will be automatically closed. Must be at
	// least 5 and no more than 600 seconds in the future; can't be used together with
	// close_period.
	//
	// Use SetCloseDate and GetCloseDate helpers.
	CloseDate int
	// CountriesISO2 field of Poll.
	//
	// Use SetCountriesISO2 and GetCountriesISO2 helpers.
	CountriesISO2 []string
	// Hash field of Poll.
	Hash int64
}

// PollTypeID is TL type id of Poll.
const PollTypeID = 0x966e2dbf

// Ensuring interfaces in compile-time for Poll.
var (
	_ bin.Encoder     = &Poll{}
	_ bin.Decoder     = &Poll{}
	_ bin.BareEncoder = &Poll{}
	_ bin.BareDecoder = &Poll{}
)

func (p *Poll) Zero() bool {
	if p == nil {
		return true
	}
	if !(p.ID == 0) {
		return false
	}
	if !(p.Flags.Zero()) {
		return false
	}
	if !(p.Closed == false) {
		return false
	}
	if !(p.PublicVoters == false) {
		return false
	}
	if !(p.MultipleChoice == false) {
		return false
	}
	if !(p.Quiz == false) {
		return false
	}
	if !(p.OpenAnswers == false) {
		return false
	}
	if !(p.RevotingDisabled == false) {
		return false
	}
	if !(p.ShuffleAnswers == false) {
		return false
	}
	if !(p.HideResultsUntilClose == false) {
		return false
	}
	if !(p.Creator == false) {
		return false
	}
	if !(p.SubscribersOnly == false) {
		return false
	}
	if !(p.Question.Zero()) {
		return false
	}
	if !(p.Answers == nil) {
		return false
	}
	if !(p.ClosePeriod == 0) {
		return false
	}
	if !(p.CloseDate == 0) {
		return false
	}
	if !(p.CountriesISO2 == nil) {
		return false
	}
	if !(p.Hash == 0) {
		return false
	}

	return true
}

// String implements fmt.Stringer.
func (p *Poll) String() string {
	if p == nil {
		return "Poll(nil)"
	}
	type Alias Poll
	return fmt.Sprintf("Poll%+v", Alias(*p))
}

// FillFrom fills Poll from given interface.
func (p *Poll) FillFrom(from interface {
	GetID() (value int64)
	GetClosed() (value bool)
	GetPublicVoters() (value bool)
	GetMultipleChoice() (value bool)
	GetQuiz() (value bool)
	GetOpenAnswers() (value bool)
	GetRevotingDisabled() (value bool)
	GetShuffleAnswers() (value bool)
	GetHideResultsUntilClose() (value bool)
	GetCreator() (value bool)
	GetSubscribersOnly() (value bool)
	GetQuestion() (value TextWithEntities)
	GetAnswers() (value []PollAnswerClass)
	GetClosePeriod() (value int, ok bool)
	GetCloseDate() (value int, ok bool)
	GetCountriesISO2() (value []string, ok bool)
	GetHash() (value int64)
}) {
	p.ID = from.GetID()
	p.Closed = from.GetClosed()
	p.PublicVoters = from.GetPublicVoters()
	p.MultipleChoice = from.GetMultipleChoice()
	p.Quiz = from.GetQuiz()
	p.OpenAnswers = from.GetOpenAnswers()
	p.RevotingDisabled = from.GetRevotingDisabled()
	p.ShuffleAnswers = from.GetShuffleAnswers()
	p.HideResultsUntilClose = from.GetHideResultsUntilClose()
	p.Creator = from.GetCreator()
	p.SubscribersOnly = from.GetSubscribersOnly()
	p.Question = from.GetQuestion()
	p.Answers = from.GetAnswers()
	if val, ok := from.GetClosePeriod(); ok {
		p.ClosePeriod = val
	}

	if val, ok := from.GetCloseDate(); ok {
		p.CloseDate = val
	}

	if val, ok := from.GetCountriesISO2(); ok {
		p.CountriesISO2 = val
	}

	p.Hash = from.GetHash()
}

// TypeID returns type id in TL schema.
//
// See https://core.telegram.org/mtproto/TL-tl#remarks.
func (*Poll) TypeID() uint32 {
	return PollTypeID
}

// TypeName returns name of type in TL schema.
func (*Poll) TypeName() string {
	return "poll"
}

// TypeInfo returns info about TL type.
func (p *Poll) TypeInfo() tdp.Type {
	typ := tdp.Type{
		Name: "poll",
		ID:   PollTypeID,
	}
	if p == nil {
		typ.Null = true
		return typ
	}
	typ.Fields = []tdp.Field{
		{
			Name:       "ID",
			SchemaName: "id",
		},
		{
			Name:       "Closed",
			SchemaName: "closed",
			Null:       !p.Flags.Has(0),
		},
		{
			Name:       "PublicVoters",
			SchemaName: "public_voters",
			Null:       !p.Flags.Has(1),
		},
		{
			Name:       "MultipleChoice",
			SchemaName: "multiple_choice",
			Null:       !p.Flags.Has(2),
		},
		{
			Name:       "Quiz",
			SchemaName: "quiz",
			Null:       !p.Flags.Has(3),
		},
		{
			Name:       "OpenAnswers",
			SchemaName: "open_answers",
			Null:       !p.Flags.Has(6),
		},
		{
			Name:       "RevotingDisabled",
			SchemaName: "revoting_disabled",
			Null:       !p.Flags.Has(7),
		},
		{
			Name:       "ShuffleAnswers",
			SchemaName: "shuffle_answers",
			Null:       !p.Flags.Has(8),
		},
		{
			Name:       "HideResultsUntilClose",
			SchemaName: "hide_results_until_close",
			Null:       !p.Flags.Has(9),
		},
		{
			Name:       "Creator",
			SchemaName: "creator",
			Null:       !p.Flags.Has(10),
		},
		{
			Name:       "SubscribersOnly",
			SchemaName: "subscribers_only",
			Null:       !p.Flags.Has(11),
		},
		{
			Name:       "Question",
			SchemaName: "question",
		},
		{
			Name:       "Answers",
			SchemaName: "answers",
		},
		{
			Name:       "ClosePeriod",
			SchemaName: "close_period",
			Null:       !p.Flags.Has(4),
		},
		{
			Name:       "CloseDate",
			SchemaName: "close_date",
			Null:       !p.Flags.Has(5),
		},
		{
			Name:       "CountriesISO2",
			SchemaName: "countries_iso2",
			Null:       !p.Flags.Has(12),
		},
		{
			Name:       "Hash",
			SchemaName: "hash",
		},
	}
	return typ
}

// SetFlags sets flags for non-zero fields.
func (p *Poll) SetFlags() {
	if !(p.Closed == false) {
		p.Flags.Set(0)
	}
	if !(p.PublicVoters == false) {
		p.Flags.Set(1)
	}
	if !(p.MultipleChoice == false) {
		p.Flags.Set(2)
	}
	if !(p.Quiz == false) {
		p.Flags.Set(3)
	}
	if !(p.OpenAnswers == false) {
		p.Flags.Set(6)
	}
	if !(p.RevotingDisabled == false) {
		p.Flags.Set(7)
	}
	if !(p.ShuffleAnswers == false) {
		p.Flags.Set(8)
	}
	if !(p.HideResultsUntilClose == false) {
		p.Flags.Set(9)
	}
	if !(p.Creator == false) {
		p.Flags.Set(10)
	}
	if !(p.SubscribersOnly == false) {
		p.Flags.Set(11)
	}
	if !(p.ClosePeriod == 0) {
		p.Flags.Set(4)
	}
	if !(p.CloseDate == 0) {
		p.Flags.Set(5)
	}
	if !(p.CountriesISO2 == nil) {
		p.Flags.Set(12)
	}
}

// Encode implements bin.Encoder.
func (p *Poll) Encode(b *bin.Buffer) error {
	if p == nil {
		return fmt.Errorf("can't encode poll#966e2dbf as nil")
	}
	b.PutID(PollTypeID)
	return p.EncodeBare(b)
}

// EncodeBare implements bin.BareEncoder.
func (p *Poll) EncodeBare(b *bin.Buffer) error {
	if p == nil {
		return fmt.Errorf("can't encode poll#966e2dbf as nil")
	}
	p.SetFlags()
	b.PutLong(p.ID)
	if err := p.Flags.Encode(b); err != nil {
		return fmt.Errorf("unable to encode poll#966e2dbf: field flags: %w", err)
	}
	if err := p.Question.Encode(b); err != nil {
		return fmt.Errorf("unable to encode poll#966e2dbf: field question: %w", err)
	}
	b.PutVectorHeader(len(p.Answers))
	for idx, v := range p.Answers {
		if v == nil {
			return fmt.Errorf("unable to encode poll#966e2dbf: field answers element with index %d is nil", idx)
		}
		if err := v.Encode(b); err != nil {
			return fmt.Errorf("unable to encode poll#966e2dbf: field answers element with index %d: %w", idx, err)
		}
	}
	if p.Flags.Has(4) {
		b.PutInt(p.ClosePeriod)
	}
	if p.Flags.Has(5) {
		b.PutInt(p.CloseDate)
	}
	if p.Flags.Has(12) {
		b.PutVectorHeader(len(p.CountriesISO2))
		for _, v := range p.CountriesISO2 {
			b.PutString(v)
		}
	}
	b.PutLong(p.Hash)
	return nil
}

// Decode implements bin.Decoder.
func (p *Poll) Decode(b *bin.Buffer) error {
	if p == nil {
		return fmt.Errorf("can't decode poll#966e2dbf to nil")
	}
	if err := b.ConsumeID(PollTypeID); err != nil {
		return fmt.Errorf("unable to decode poll#966e2dbf: %w", err)
	}
	return p.DecodeBare(b)
}

// DecodeBare implements bin.BareDecoder.
func (p *Poll) DecodeBare(b *bin.Buffer) error {
	if p == nil {
		return fmt.Errorf("can't decode poll#966e2dbf to nil")
	}
	{
		value, err := b.Long()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field id: %w", err)
		}
		p.ID = value
	}
	{
		if err := p.Flags.Decode(b); err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field flags: %w", err)
		}
	}
	p.Closed = p.Flags.Has(0)
	p.PublicVoters = p.Flags.Has(1)
	p.MultipleChoice = p.Flags.Has(2)
	p.Quiz = p.Flags.Has(3)
	p.OpenAnswers = p.Flags.Has(6)
	p.RevotingDisabled = p.Flags.Has(7)
	p.ShuffleAnswers = p.Flags.Has(8)
	p.HideResultsUntilClose = p.Flags.Has(9)
	p.Creator = p.Flags.Has(10)
	p.SubscribersOnly = p.Flags.Has(11)
	{
		if err := p.Question.Decode(b); err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field question: %w", err)
		}
	}
	{
		headerLen, err := b.VectorHeader()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field answers: %w", err)
		}

		if headerLen > 0 {
			p.Answers = make([]PollAnswerClass, 0, headerLen%bin.PreallocateLimit)
		}
		for idx := 0; idx < headerLen; idx++ {
			value, err := DecodePollAnswer(b)
			if err != nil {
				return fmt.Errorf("unable to decode poll#966e2dbf: field answers: %w", err)
			}
			p.Answers = append(p.Answers, value)
		}
	}
	if p.Flags.Has(4) {
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field close_period: %w", err)
		}
		p.ClosePeriod = value
	}
	if p.Flags.Has(5) {
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field close_date: %w", err)
		}
		p.CloseDate = value
	}
	if p.Flags.Has(12) {
		headerLen, err := b.VectorHeader()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field countries_iso2: %w", err)
		}

		if headerLen > 0 {
			p.CountriesISO2 = make([]string, 0, headerLen%bin.PreallocateLimit)
		}
		for idx := 0; idx < headerLen; idx++ {
			value, err := b.String()
			if err != nil {
				return fmt.Errorf("unable to decode poll#966e2dbf: field countries_iso2: %w", err)
			}
			p.CountriesISO2 = append(p.CountriesISO2, value)
		}
	}
	{
		value, err := b.Long()
		if err != nil {
			return fmt.Errorf("unable to decode poll#966e2dbf: field hash: %w", err)
		}
		p.Hash = value
	}
	return nil
}

// GetID returns value of ID field.
func (p *Poll) GetID() (value int64) {
	if p == nil {
		return
	}
	return p.ID
}

// SetClosed sets value of Closed conditional field.
func (p *Poll) SetClosed(value bool) {
	if value {
		p.Flags.Set(0)
		p.Closed = true
	} else {
		p.Flags.Unset(0)
		p.Closed = false
	}
}

// GetClosed returns value of Closed conditional field.
func (p *Poll) GetClosed() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(0)
}

// SetPublicVoters sets value of PublicVoters conditional field.
func (p *Poll) SetPublicVoters(value bool) {
	if value {
		p.Flags.Set(1)
		p.PublicVoters = true
	} else {
		p.Flags.Unset(1)
		p.PublicVoters = false
	}
}

// GetPublicVoters returns value of PublicVoters conditional field.
func (p *Poll) GetPublicVoters() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(1)
}

// SetMultipleChoice sets value of MultipleChoice conditional field.
func (p *Poll) SetMultipleChoice(value bool) {
	if value {
		p.Flags.Set(2)
		p.MultipleChoice = true
	} else {
		p.Flags.Unset(2)
		p.MultipleChoice = false
	}
}

// GetMultipleChoice returns value of MultipleChoice conditional field.
func (p *Poll) GetMultipleChoice() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(2)
}

// SetQuiz sets value of Quiz conditional field.
func (p *Poll) SetQuiz(value bool) {
	if value {
		p.Flags.Set(3)
		p.Quiz = true
	} else {
		p.Flags.Unset(3)
		p.Quiz = false
	}
}

// GetQuiz returns value of Quiz conditional field.
func (p *Poll) GetQuiz() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(3)
}

// SetOpenAnswers sets value of OpenAnswers conditional field.
func (p *Poll) SetOpenAnswers(value bool) {
	if value {
		p.Flags.Set(6)
		p.OpenAnswers = true
	} else {
		p.Flags.Unset(6)
		p.OpenAnswers = false
	}
}

// GetOpenAnswers returns value of OpenAnswers conditional field.
func (p *Poll) GetOpenAnswers() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(6)
}

// SetRevotingDisabled sets value of RevotingDisabled conditional field.
func (p *Poll) SetRevotingDisabled(value bool) {
	if value {
		p.Flags.Set(7)
		p.RevotingDisabled = true
	} else {
		p.Flags.Unset(7)
		p.RevotingDisabled = false
	}
}

// GetRevotingDisabled returns value of RevotingDisabled conditional field.
func (p *Poll) GetRevotingDisabled() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(7)
}

// SetShuffleAnswers sets value of ShuffleAnswers conditional field.
func (p *Poll) SetShuffleAnswers(value bool) {
	if value {
		p.Flags.Set(8)
		p.ShuffleAnswers = true
	} else {
		p.Flags.Unset(8)
		p.ShuffleAnswers = false
	}
}

// GetShuffleAnswers returns value of ShuffleAnswers conditional field.
func (p *Poll) GetShuffleAnswers() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(8)
}

// SetHideResultsUntilClose sets value of HideResultsUntilClose conditional field.
func (p *Poll) SetHideResultsUntilClose(value bool) {
	if value {
		p.Flags.Set(9)
		p.HideResultsUntilClose = true
	} else {
		p.Flags.Unset(9)
		p.HideResultsUntilClose = false
	}
}

// GetHideResultsUntilClose returns value of HideResultsUntilClose conditional field.
func (p *Poll) GetHideResultsUntilClose() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(9)
}

// SetCreator sets value of Creator conditional field.
func (p *Poll) SetCreator(value bool) {
	if value {
		p.Flags.Set(10)
		p.Creator = true
	} else {
		p.Flags.Unset(10)
		p.Creator = false
	}
}

// GetCreator returns value of Creator conditional field.
func (p *Poll) GetCreator() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(10)
}

// SetSubscribersOnly sets value of SubscribersOnly conditional field.
func (p *Poll) SetSubscribersOnly(value bool) {
	if value {
		p.Flags.Set(11)
		p.SubscribersOnly = true
	} else {
		p.Flags.Unset(11)
		p.SubscribersOnly = false
	}
}

// GetSubscribersOnly returns value of SubscribersOnly conditional field.
func (p *Poll) GetSubscribersOnly() (value bool) {
	if p == nil {
		return
	}
	return p.Flags.Has(11)
}

// GetQuestion returns value of Question field.
func (p *Poll) GetQuestion() (value TextWithEntities) {
	if p == nil {
		return
	}
	return p.Question
}

// GetAnswers returns value of Answers field.
func (p *Poll) GetAnswers() (value []PollAnswerClass) {
	if p == nil {
		return
	}
	return p.Answers
}

// SetClosePeriod sets value of ClosePeriod conditional field.
func (p *Poll) SetClosePeriod(value int) {
	p.Flags.Set(4)
	p.ClosePeriod = value
}

// GetClosePeriod returns value of ClosePeriod conditional field and
// boolean which is true if field was set.
func (p *Poll) GetClosePeriod() (value int, ok bool) {
	if p == nil {
		return
	}
	if !p.Flags.Has(4) {
		return value, false
	}
	return p.ClosePeriod, true
}

// SetCloseDate sets value of CloseDate conditional field.
func (p *Poll) SetCloseDate(value int) {
	p.Flags.Set(5)
	p.CloseDate = value
}

// GetCloseDate returns value of CloseDate conditional field and
// boolean which is true if field was set.
func (p *Poll) GetCloseDate() (value int, ok bool) {
	if p == nil {
		return
	}
	if !p.Flags.Has(5) {
		return value, false
	}
	return p.CloseDate, true
}

// SetCountriesISO2 sets value of CountriesISO2 conditional field.
func (p *Poll) SetCountriesISO2(value []string) {
	p.Flags.Set(12)
	p.CountriesISO2 = value
}

// GetCountriesISO2 returns value of CountriesISO2 conditional field and
// boolean which is true if field was set.
func (p *Poll) GetCountriesISO2() (value []string, ok bool) {
	if p == nil {
		return
	}
	if !p.Flags.Has(12) {
		return value, false
	}
	return p.CountriesISO2, true
}

// GetHash returns value of Hash field.
func (p *Poll) GetHash() (value int64) {
	if p == nil {
		return
	}
	return p.Hash
}

// MapAnswers returns field Answers wrapped in PollAnswerClassArray helper.
func (p *Poll) MapAnswers() (value PollAnswerClassArray) {
	return PollAnswerClassArray(p.Answers)
}
