// 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{}
)

// MessageFwdHeader represents TL type `messageFwdHeader#4e4df4bb`.
// Info about a forwarded message
//
// See https://core.telegram.org/constructor/messageFwdHeader for reference.
type MessageFwdHeader struct {
	// Flags, see TL conditional fields¹
	//
	// Links:
	//  1) https://core.telegram.org/mtproto/TL-combinators#conditional-fields
	Flags bin.Fields
	// Whether this message was imported from a foreign chat service, click here for more
	// info »¹
	//
	// Links:
	//  1) https://core.telegram.org/api/import
	Imported bool
	// Only for messages forwarded to saved messages »¹, set if the original message was
	// outgoing (though the message may have been originally outgoing even if this flag is
	// not set, if from_id points to the current user).
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	SavedOut bool
	// The ID of the user that originally sent the message
	//
	// Use SetFromID and GetFromID helpers.
	FromID PeerClass
	// The name of the user that originally sent the message
	//
	// Use SetFromName and GetFromName helpers.
	FromName string
	// When was the message originally sent
	Date int
	// ID of the channel message that was forwarded
	//
	// Use SetChannelPost and GetChannelPost helpers.
	ChannelPost int
	// For channels and if signatures are enabled, author of the channel message
	//
	// Use SetPostAuthor and GetPostAuthor helpers.
	PostAuthor string
	// Only for messages forwarded to saved messages »¹, contains the dialog where the
	// message was originally sent.
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	//
	// Use SetSavedFromPeer and GetSavedFromPeer helpers.
	SavedFromPeer PeerClass
	// Only for messages forwarded to saved messages »¹, contains the original ID of the
	// message in saved_from_peer.
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	//
	// Use SetSavedFromMsgID and GetSavedFromMsgID helpers.
	SavedFromMsgID int
	// Only for forwarded messages reforwarded to saved messages »¹, contains the sender of
	// the original message (i.e. if user A sends a message, then user B forwards it
	// somewhere, then user C saves it to saved messages, this field will contain the ID of
	// user B and from_id will contain the ID of user A).
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	//
	// Use SetSavedFromID and GetSavedFromID helpers.
	SavedFromID PeerClass
	// Only for forwarded messages from users with forward privacy enabled, sent by users
	// with forward privacy enabled, reforwarded to saved messages »¹, contains the sender
	// of the original message (i.e. if user A (fwd privacy enabled) sends a message, then
	// user B (fwd privacy enabled) forwards it somewhere, then user C saves it to saved
	// messages, this field will contain the name of user B and from_name will contain the
	// name of user A).
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	//
	// Use SetSavedFromName and GetSavedFromName helpers.
	SavedFromName string
	// Only for forwarded messages reforwarded to saved messages »¹, indicates when was the
	// original message sent (i.e. if user A sends a message @ unixtime 1, then user B
	// forwards it somewhere @ unixtime 2, then user C saves it to saved messages @ unixtime
	// 3, this field will contain 2, date will contain 1 and the date of the containing
	// message² will contain 3).
	//
	// Links:
	//  1) https://core.telegram.org/api/saved-messages
	//  2) https://core.telegram.org/constructor/message
	//
	// Use SetSavedDate and GetSavedDate helpers.
	SavedDate int
	// PSA type
	//
	// Use SetPsaType and GetPsaType helpers.
	PsaType string
}

// MessageFwdHeaderTypeID is TL type id of MessageFwdHeader.
const MessageFwdHeaderTypeID = 0x4e4df4bb

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

func (m *MessageFwdHeader) Zero() bool {
	if m == nil {
		return true
	}
	if !(m.Flags.Zero()) {
		return false
	}
	if !(m.Imported == false) {
		return false
	}
	if !(m.SavedOut == false) {
		return false
	}
	if !(m.FromID == nil) {
		return false
	}
	if !(m.FromName == "") {
		return false
	}
	if !(m.Date == 0) {
		return false
	}
	if !(m.ChannelPost == 0) {
		return false
	}
	if !(m.PostAuthor == "") {
		return false
	}
	if !(m.SavedFromPeer == nil) {
		return false
	}
	if !(m.SavedFromMsgID == 0) {
		return false
	}
	if !(m.SavedFromID == nil) {
		return false
	}
	if !(m.SavedFromName == "") {
		return false
	}
	if !(m.SavedDate == 0) {
		return false
	}
	if !(m.PsaType == "") {
		return false
	}

	return true
}

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

// FillFrom fills MessageFwdHeader from given interface.
func (m *MessageFwdHeader) FillFrom(from interface {
	GetImported() (value bool)
	GetSavedOut() (value bool)
	GetFromID() (value PeerClass, ok bool)
	GetFromName() (value string, ok bool)
	GetDate() (value int)
	GetChannelPost() (value int, ok bool)
	GetPostAuthor() (value string, ok bool)
	GetSavedFromPeer() (value PeerClass, ok bool)
	GetSavedFromMsgID() (value int, ok bool)
	GetSavedFromID() (value PeerClass, ok bool)
	GetSavedFromName() (value string, ok bool)
	GetSavedDate() (value int, ok bool)
	GetPsaType() (value string, ok bool)
}) {
	m.Imported = from.GetImported()
	m.SavedOut = from.GetSavedOut()
	if val, ok := from.GetFromID(); ok {
		m.FromID = val
	}

	if val, ok := from.GetFromName(); ok {
		m.FromName = val
	}

	m.Date = from.GetDate()
	if val, ok := from.GetChannelPost(); ok {
		m.ChannelPost = val
	}

	if val, ok := from.GetPostAuthor(); ok {
		m.PostAuthor = val
	}

	if val, ok := from.GetSavedFromPeer(); ok {
		m.SavedFromPeer = val
	}

	if val, ok := from.GetSavedFromMsgID(); ok {
		m.SavedFromMsgID = val
	}

	if val, ok := from.GetSavedFromID(); ok {
		m.SavedFromID = val
	}

	if val, ok := from.GetSavedFromName(); ok {
		m.SavedFromName = val
	}

	if val, ok := from.GetSavedDate(); ok {
		m.SavedDate = val
	}

	if val, ok := from.GetPsaType(); ok {
		m.PsaType = val
	}

}

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

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

// TypeInfo returns info about TL type.
func (m *MessageFwdHeader) TypeInfo() tdp.Type {
	typ := tdp.Type{
		Name: "messageFwdHeader",
		ID:   MessageFwdHeaderTypeID,
	}
	if m == nil {
		typ.Null = true
		return typ
	}
	typ.Fields = []tdp.Field{
		{
			Name:       "Imported",
			SchemaName: "imported",
			Null:       !m.Flags.Has(7),
		},
		{
			Name:       "SavedOut",
			SchemaName: "saved_out",
			Null:       !m.Flags.Has(11),
		},
		{
			Name:       "FromID",
			SchemaName: "from_id",
			Null:       !m.Flags.Has(0),
		},
		{
			Name:       "FromName",
			SchemaName: "from_name",
			Null:       !m.Flags.Has(5),
		},
		{
			Name:       "Date",
			SchemaName: "date",
		},
		{
			Name:       "ChannelPost",
			SchemaName: "channel_post",
			Null:       !m.Flags.Has(2),
		},
		{
			Name:       "PostAuthor",
			SchemaName: "post_author",
			Null:       !m.Flags.Has(3),
		},
		{
			Name:       "SavedFromPeer",
			SchemaName: "saved_from_peer",
			Null:       !m.Flags.Has(4),
		},
		{
			Name:       "SavedFromMsgID",
			SchemaName: "saved_from_msg_id",
			Null:       !m.Flags.Has(4),
		},
		{
			Name:       "SavedFromID",
			SchemaName: "saved_from_id",
			Null:       !m.Flags.Has(8),
		},
		{
			Name:       "SavedFromName",
			SchemaName: "saved_from_name",
			Null:       !m.Flags.Has(9),
		},
		{
			Name:       "SavedDate",
			SchemaName: "saved_date",
			Null:       !m.Flags.Has(10),
		},
		{
			Name:       "PsaType",
			SchemaName: "psa_type",
			Null:       !m.Flags.Has(6),
		},
	}
	return typ
}

// SetFlags sets flags for non-zero fields.
func (m *MessageFwdHeader) SetFlags() {
	if !(m.Imported == false) {
		m.Flags.Set(7)
	}
	if !(m.SavedOut == false) {
		m.Flags.Set(11)
	}
	if !(m.FromID == nil) {
		m.Flags.Set(0)
	}
	if !(m.FromName == "") {
		m.Flags.Set(5)
	}
	if !(m.ChannelPost == 0) {
		m.Flags.Set(2)
	}
	if !(m.PostAuthor == "") {
		m.Flags.Set(3)
	}
	if !(m.SavedFromPeer == nil) {
		m.Flags.Set(4)
	}
	if !(m.SavedFromMsgID == 0) {
		m.Flags.Set(4)
	}
	if !(m.SavedFromID == nil) {
		m.Flags.Set(8)
	}
	if !(m.SavedFromName == "") {
		m.Flags.Set(9)
	}
	if !(m.SavedDate == 0) {
		m.Flags.Set(10)
	}
	if !(m.PsaType == "") {
		m.Flags.Set(6)
	}
}

// Encode implements bin.Encoder.
func (m *MessageFwdHeader) Encode(b *bin.Buffer) error {
	if m == nil {
		return fmt.Errorf("can't encode messageFwdHeader#4e4df4bb as nil")
	}
	b.PutID(MessageFwdHeaderTypeID)
	return m.EncodeBare(b)
}

// EncodeBare implements bin.BareEncoder.
func (m *MessageFwdHeader) EncodeBare(b *bin.Buffer) error {
	if m == nil {
		return fmt.Errorf("can't encode messageFwdHeader#4e4df4bb as nil")
	}
	m.SetFlags()
	if err := m.Flags.Encode(b); err != nil {
		return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field flags: %w", err)
	}
	if m.Flags.Has(0) {
		if m.FromID == nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field from_id is nil")
		}
		if err := m.FromID.Encode(b); err != nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field from_id: %w", err)
		}
	}
	if m.Flags.Has(5) {
		b.PutString(m.FromName)
	}
	b.PutInt(m.Date)
	if m.Flags.Has(2) {
		b.PutInt(m.ChannelPost)
	}
	if m.Flags.Has(3) {
		b.PutString(m.PostAuthor)
	}
	if m.Flags.Has(4) {
		if m.SavedFromPeer == nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field saved_from_peer is nil")
		}
		if err := m.SavedFromPeer.Encode(b); err != nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field saved_from_peer: %w", err)
		}
	}
	if m.Flags.Has(4) {
		b.PutInt(m.SavedFromMsgID)
	}
	if m.Flags.Has(8) {
		if m.SavedFromID == nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field saved_from_id is nil")
		}
		if err := m.SavedFromID.Encode(b); err != nil {
			return fmt.Errorf("unable to encode messageFwdHeader#4e4df4bb: field saved_from_id: %w", err)
		}
	}
	if m.Flags.Has(9) {
		b.PutString(m.SavedFromName)
	}
	if m.Flags.Has(10) {
		b.PutInt(m.SavedDate)
	}
	if m.Flags.Has(6) {
		b.PutString(m.PsaType)
	}
	return nil
}

// Decode implements bin.Decoder.
func (m *MessageFwdHeader) Decode(b *bin.Buffer) error {
	if m == nil {
		return fmt.Errorf("can't decode messageFwdHeader#4e4df4bb to nil")
	}
	if err := b.ConsumeID(MessageFwdHeaderTypeID); err != nil {
		return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: %w", err)
	}
	return m.DecodeBare(b)
}

// DecodeBare implements bin.BareDecoder.
func (m *MessageFwdHeader) DecodeBare(b *bin.Buffer) error {
	if m == nil {
		return fmt.Errorf("can't decode messageFwdHeader#4e4df4bb to nil")
	}
	{
		if err := m.Flags.Decode(b); err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field flags: %w", err)
		}
	}
	m.Imported = m.Flags.Has(7)
	m.SavedOut = m.Flags.Has(11)
	if m.Flags.Has(0) {
		value, err := DecodePeer(b)
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field from_id: %w", err)
		}
		m.FromID = value
	}
	if m.Flags.Has(5) {
		value, err := b.String()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field from_name: %w", err)
		}
		m.FromName = value
	}
	{
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field date: %w", err)
		}
		m.Date = value
	}
	if m.Flags.Has(2) {
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field channel_post: %w", err)
		}
		m.ChannelPost = value
	}
	if m.Flags.Has(3) {
		value, err := b.String()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field post_author: %w", err)
		}
		m.PostAuthor = value
	}
	if m.Flags.Has(4) {
		value, err := DecodePeer(b)
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field saved_from_peer: %w", err)
		}
		m.SavedFromPeer = value
	}
	if m.Flags.Has(4) {
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field saved_from_msg_id: %w", err)
		}
		m.SavedFromMsgID = value
	}
	if m.Flags.Has(8) {
		value, err := DecodePeer(b)
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field saved_from_id: %w", err)
		}
		m.SavedFromID = value
	}
	if m.Flags.Has(9) {
		value, err := b.String()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field saved_from_name: %w", err)
		}
		m.SavedFromName = value
	}
	if m.Flags.Has(10) {
		value, err := b.Int()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field saved_date: %w", err)
		}
		m.SavedDate = value
	}
	if m.Flags.Has(6) {
		value, err := b.String()
		if err != nil {
			return fmt.Errorf("unable to decode messageFwdHeader#4e4df4bb: field psa_type: %w", err)
		}
		m.PsaType = value
	}
	return nil
}

// SetImported sets value of Imported conditional field.
func (m *MessageFwdHeader) SetImported(value bool) {
	if value {
		m.Flags.Set(7)
		m.Imported = true
	} else {
		m.Flags.Unset(7)
		m.Imported = false
	}
}

// GetImported returns value of Imported conditional field.
func (m *MessageFwdHeader) GetImported() (value bool) {
	if m == nil {
		return
	}
	return m.Flags.Has(7)
}

// SetSavedOut sets value of SavedOut conditional field.
func (m *MessageFwdHeader) SetSavedOut(value bool) {
	if value {
		m.Flags.Set(11)
		m.SavedOut = true
	} else {
		m.Flags.Unset(11)
		m.SavedOut = false
	}
}

// GetSavedOut returns value of SavedOut conditional field.
func (m *MessageFwdHeader) GetSavedOut() (value bool) {
	if m == nil {
		return
	}
	return m.Flags.Has(11)
}

// SetFromID sets value of FromID conditional field.
func (m *MessageFwdHeader) SetFromID(value PeerClass) {
	m.Flags.Set(0)
	m.FromID = value
}

// GetFromID returns value of FromID conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetFromID() (value PeerClass, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(0) {
		return value, false
	}
	return m.FromID, true
}

// SetFromName sets value of FromName conditional field.
func (m *MessageFwdHeader) SetFromName(value string) {
	m.Flags.Set(5)
	m.FromName = value
}

// GetFromName returns value of FromName conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetFromName() (value string, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(5) {
		return value, false
	}
	return m.FromName, true
}

// GetDate returns value of Date field.
func (m *MessageFwdHeader) GetDate() (value int) {
	if m == nil {
		return
	}
	return m.Date
}

// SetChannelPost sets value of ChannelPost conditional field.
func (m *MessageFwdHeader) SetChannelPost(value int) {
	m.Flags.Set(2)
	m.ChannelPost = value
}

// GetChannelPost returns value of ChannelPost conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetChannelPost() (value int, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(2) {
		return value, false
	}
	return m.ChannelPost, true
}

// SetPostAuthor sets value of PostAuthor conditional field.
func (m *MessageFwdHeader) SetPostAuthor(value string) {
	m.Flags.Set(3)
	m.PostAuthor = value
}

// GetPostAuthor returns value of PostAuthor conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetPostAuthor() (value string, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(3) {
		return value, false
	}
	return m.PostAuthor, true
}

// SetSavedFromPeer sets value of SavedFromPeer conditional field.
func (m *MessageFwdHeader) SetSavedFromPeer(value PeerClass) {
	m.Flags.Set(4)
	m.SavedFromPeer = value
}

// GetSavedFromPeer returns value of SavedFromPeer conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetSavedFromPeer() (value PeerClass, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(4) {
		return value, false
	}
	return m.SavedFromPeer, true
}

// SetSavedFromMsgID sets value of SavedFromMsgID conditional field.
func (m *MessageFwdHeader) SetSavedFromMsgID(value int) {
	m.Flags.Set(4)
	m.SavedFromMsgID = value
}

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

// SetSavedFromID sets value of SavedFromID conditional field.
func (m *MessageFwdHeader) SetSavedFromID(value PeerClass) {
	m.Flags.Set(8)
	m.SavedFromID = value
}

// GetSavedFromID returns value of SavedFromID conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetSavedFromID() (value PeerClass, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(8) {
		return value, false
	}
	return m.SavedFromID, true
}

// SetSavedFromName sets value of SavedFromName conditional field.
func (m *MessageFwdHeader) SetSavedFromName(value string) {
	m.Flags.Set(9)
	m.SavedFromName = value
}

// GetSavedFromName returns value of SavedFromName conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetSavedFromName() (value string, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(9) {
		return value, false
	}
	return m.SavedFromName, true
}

// SetSavedDate sets value of SavedDate conditional field.
func (m *MessageFwdHeader) SetSavedDate(value int) {
	m.Flags.Set(10)
	m.SavedDate = value
}

// GetSavedDate returns value of SavedDate conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetSavedDate() (value int, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(10) {
		return value, false
	}
	return m.SavedDate, true
}

// SetPsaType sets value of PsaType conditional field.
func (m *MessageFwdHeader) SetPsaType(value string) {
	m.Flags.Set(6)
	m.PsaType = value
}

// GetPsaType returns value of PsaType conditional field and
// boolean which is true if field was set.
func (m *MessageFwdHeader) GetPsaType() (value string, ok bool) {
	if m == nil {
		return
	}
	if !m.Flags.Has(6) {
		return value, false
	}
	return m.PsaType, true
}
