package crypto

import (
	
	
	

	
	

	
)

// BindAuthKeyInnerTypeID is TL type id for bind_auth_key_inner.
const BindAuthKeyInnerTypeID = 0x75a3f765

// BindAuthKeyInner is a temporary auth key binding payload.
//
// bind_auth_key_inner#75a3f765 nonce:long temp_auth_key_id:long
//
//	perm_auth_key_id:long temp_session_id:long expires_at:int = BindAuthKeyInner
type BindAuthKeyInner struct {
	Nonce         int64
	TempAuthKeyID int64
	PermAuthKeyID int64
	TempSessionID int64
	ExpiresAt     int
}

// TypeID returns TL type id.
func (*BindAuthKeyInner) () uint32 {
	return BindAuthKeyInnerTypeID
}

// Encode implements bin.Encoder.
func ( *BindAuthKeyInner) ( *bin.Buffer) error {
	if  == nil {
		return fmt.Errorf("can't encode bind_auth_key_inner#75a3f765 as nil")
	}
	.PutID(BindAuthKeyInnerTypeID)
	.PutLong(.Nonce)
	.PutLong(.TempAuthKeyID)
	.PutLong(.PermAuthKeyID)
	.PutLong(.TempSessionID)
	.PutInt(.ExpiresAt)
	return nil
}

// Decode implements bin.Decoder.
func ( *BindAuthKeyInner) ( *bin.Buffer) error {
	if  == nil {
		return fmt.Errorf("can't decode bind_auth_key_inner#75a3f765 to nil")
	}
	if  := .ConsumeID(BindAuthKeyInnerTypeID);  != nil {
		return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: %w", )
	}
	{
		,  := .Long()
		if  != nil {
			return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: field nonce: %w", )
		}
		.Nonce = 
	}
	{
		,  := .Long()
		if  != nil {
			return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: field temp_auth_key_id: %w", )
		}
		.TempAuthKeyID = 
	}
	{
		,  := .Long()
		if  != nil {
			return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: field perm_auth_key_id: %w", )
		}
		.PermAuthKeyID = 
	}
	{
		,  := .Long()
		if  != nil {
			return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: field temp_session_id: %w", )
		}
		.TempSessionID = 
	}
	{
		,  := .Int()
		if  != nil {
			return fmt.Errorf("unable to decode bind_auth_key_inner#75a3f765: field expires_at: %w", )
		}
		.ExpiresAt = 
	}
	return nil
}

// EncryptBindMessage encrypts binding message using permanent key and MTProto v1 KDF.
//
// This helper exists specifically for auth.bindTempAuthKey flow where Telegram
// requires a legacy MTProto v1 envelope/KDF even if the transport session uses
// modern MTProto 2.0 packets for regular API traffic.
//
// Result format:
//
//	perm_auth_key_id(8) + msg_key(16) + encrypted_data
func ( io.Reader,  AuthKey,  int64,  *BindAuthKeyInner) ([]byte, error) {
	if .Zero() {
		return nil, errors.New("permanent key is zero")
	}
	if  == nil {
		 = DefaultRand()
	}

	 := &bin.Buffer{}
	if  := .Encode();  != nil {
		return nil, errors.Wrap(, "encode bind_auth_key_inner")
	}

	// Binding encrypted message envelope:
	// random:int128 + msg_id:long + seq_no:int + msg_len:int + message + padding.
	//
	// Quote (Special binding message): "msg_key = substr(sha1(message_data), 4, 16)."
	// Link: https://core.telegram.org/api/pfs#special-binding-message
	//
	// Here message_data is the plaintext envelope before random padding.
	 := &bin.Buffer{}
	 := make([]byte, 16)
	if ,  := io.ReadFull(, );  != nil {
		return nil, errors.Wrap(, "generate random prefix")
	}
	.Put()
	.PutLong()
	.PutInt32(0)
	.PutInt32(int32(.Len()))
	.Put(.Buf)

	// Important: for binding message msg_key is calculated from the envelope
	// without random padding, so we do it before alignment bytes are appended.
	 := MessageKeyV1(.Buf)

	if  := len(.Buf) % aes.BlockSize;  != 0 {
		 := aes.BlockSize - 
		 := len(.Buf)
		.Buf = append(.Buf, make([]byte, )...)
		if ,  := io.ReadFull(, .Buf[:]);  != nil {
			return nil, errors.Wrap(, "generate random padding")
		}
	}

	// Binding message uses KDF v1 with permanent key material.
	,  := KeysV1(.Value, )
	,  := aes.NewCipher([:])
	if  != nil {
		return nil, errors.Wrap(, "create aes cipher")
	}

	// Quote (Method docs): "prepend perm_auth_key_id and msg_key as usual".
	// Link: https://core.telegram.org/method/auth.bindTempAuthKey
	//
	// For this method, encrypted_message includes auth_key_id + msg_key + encrypted_data.
	 := EncryptedMessage{
		AuthKeyID:     .ID,
		MsgKey:        ,
		EncryptedData: make([]byte, len(.Buf)),
	}
	ige.EncryptBlocks(, [:], .EncryptedData, .Buf)

	 := &bin.Buffer{}
	if  := .Encode();  != nil {
		return nil, errors.Wrap(, "encode encrypted message")
	}
	return append([]byte(nil), .Buf...), nil
}