package mtproto

import (
	

	
	

	
	
	
	
)

const maxBindTempAuthKeyAttempts = 3

func ( *Conn) ( context.Context) error {
	var  error
	for  := 1;  <= maxBindTempAuthKeyAttempts; ++ {
		 := .bindTempAuthKeyAttempt()
		if  == nil {
			return nil
		}
		 = 

		if tgerr.Is(, tg.ErrEncryptedMessageInvalid) {
			if  := .handleBindEncryptedMessageInvalid();  != nil {
				return 
			}
			continue
		}
		if tgerr.Is(, "CONNECTION_NOT_INITED") {
			if  := .handleBindConnectionNotInited();  != nil {
				return 
			}
			// Retry same bind call on transient ordering/race conditions.
			continue
		}
		return 
	}

	return errors.Wrap(, "temporary auth key bind retry limit reached")
}

func ( *Conn) ( context.Context) error {
	 := .session()
	if .Key.Zero() {
		return errors.New("temporary key is zero")
	}
	if .PermKey.Zero() {
		return errors.New("permanent key is zero")
	}
	if .ID == 0 {
		return errors.New("temporary session id is zero")
	}

	.sessionMux.RLock()
	 := .tempKeyExpiry
	.sessionMux.RUnlock()
	if  == 0 {
		 = .clock.Now().Unix() + int64(.tempKeyTTL)
	}

	,  := crypto.RandInt64(.rand)
	if  != nil {
		return errors.Wrap(, "generate nonce")
	}
	 := &crypto.BindAuthKeyInner{
		Nonce:         ,
		TempAuthKeyID: .Key.IntID(),
		PermAuthKeyID: .PermKey.IntID(),
		TempSessionID: .ID,
		ExpiresAt:     int(),
	}

	// bindTempAuthKey is a content-related request and must consume normal
	// msg_id/seq_no progression to remain valid in current temp session.
	,  := .nextMsgSeq(true)

	,  := crypto.EncryptBindMessage(
		.rand,
		.PermKey,
		,
		,
	)
	if  != nil {
		return errors.Wrap(, "encrypt bind message")
	}

	 := &tg.AuthBindTempAuthKeyRequest{
		PermAuthKeyID:    .PermKey.IntID(),
		Nonce:            ,
		ExpiresAt:        int(),
		EncryptedMessage: ,
	}

	var  tg.BoolBox
	 := rpc.Request{
		MsgID:  ,
		SeqNo:  ,
		Input:  ,
		Output: &,
	}
	.log.Debug(, "Binding temporary auth key",
		log.Int64("temp_key_id", .Key.IntID()),
		log.Int64("perm_key_id", .PermKey.IntID()),
		log.Int64("temp_session_id", .ID),
		log.Int64("expires_at", ),
	)

	if  := .rpc.Do(, );  != nil {
		var  *badMessageError
		if errors.As(, &) && .Code == codeIncorrectServerSalt {
			.storeSalt(.NewSalt)
			.salts.Reset()
			if  := .rpc.Do(, );  != nil {
				return errors.Wrap(, "invoke auth.bindTempAuthKey")
			}
		} else {
			return errors.Wrap(, "invoke auth.bindTempAuthKey")
		}
	}

	if ,  := .Bool.(*tg.BoolTrue); ! {
		return errors.New("temp auth key bind rejected")
	}
	.log.Info(, "Temporary auth key bound",
		log.Int64("temp_key_id", .Key.IntID()),
		log.Int64("perm_key_id", .PermKey.IntID()),
		log.Int64("expires_at", ),
	)
	return nil
}

func ( *Conn) ( int) error {
	// Quote (PFS): "if auth.bindTempAuthKey returns ENCRYPTED_MESSAGE_INVALID
	// and the permanent key was generated more than 60 seconds ago, both keys
	// should be dropped and generated again."
	// Link: https://core.telegram.org/api/pfs
	if .permKeyOlderThan60s() {
		.log.Warn(context.Background(), "auth.bindTempAuthKey returned ENCRYPTED_MESSAGE_INVALID for old permanent key, dropping persisted PFS keys and reconnecting",
			log.Int("attempt", ),
		)
		.dropPFSKeys()
		return errors.Wrap(ErrPFSDropKeysRequired, "pfs keys dropped after ENCRYPTED_MESSAGE_INVALID")
	}

	if !.permKeyAgeKnown() {
		// For restored sessions key age is unknown, so we first follow retry path.
		// If all retries fail, force key regeneration to avoid endless reconnect loop.
		if  >= maxBindTempAuthKeyAttempts {
			.log.Warn(context.Background(), "auth.bindTempAuthKey returned ENCRYPTED_MESSAGE_INVALID for key with unknown age after retries, dropping persisted PFS keys and reconnecting",
				log.Int("attempt", ),
			)
			.dropPFSKeys()
			return errors.Wrap(ErrPFSDropKeysRequired, "pfs keys dropped after repeated ENCRYPTED_MESSAGE_INVALID with unknown key age")
		}
		.log.Warn(context.Background(), "auth.bindTempAuthKey returned ENCRYPTED_MESSAGE_INVALID for key with unknown age, retrying bind before dropping keys",
			log.Int("attempt", ),
		)
		return nil
	}

	// Quote (PFS): "Otherwise, the client should simply retry binding."
	// Link: https://core.telegram.org/api/pfs
	.log.Warn(context.Background(), "auth.bindTempAuthKey returned ENCRYPTED_MESSAGE_INVALID for fresh permanent key, retrying bind",
		log.Int("attempt", ),
	)
	return nil
}

func ( *Conn) ( int) error {
	if  < maxBindTempAuthKeyAttempts {
		// In practice this can happen while server-side state is catching up;
		// avoid aggressive key reset and retry bind first.
		.log.Warn(context.Background(), "auth.bindTempAuthKey returned CONNECTION_NOT_INITED, retrying bind",
			log.Int("attempt", ),
		)
		return nil
	}
	// After retries, reconnect whole transport/session and run full init path.
	.log.Warn(context.Background(), "auth.bindTempAuthKey returned CONNECTION_NOT_INITED after retries, reconnecting without dropping keys",
		log.Int("attempt", ),
	)
	return errors.New("auth.bindTempAuthKey failed with CONNECTION_NOT_INITED after retries")
}

func ( *Conn) () bool {
	.sessionMux.RLock()
	 := .permKeyCreatedAt != 0
	.sessionMux.RUnlock()
	return 
}

func ( *Conn) () bool {
	.sessionMux.RLock()
	 := .permKeyCreatedAt
	.sessionMux.RUnlock()
	if  == 0 {
		return false
	}
	return .clock.Now().Unix()- > 60
}

func ( *Conn) () {
	.sessionMux.Lock()
	.authKey = crypto.AuthKey{}
	.permKey = crypto.AuthKey{}
	.permKeyCreatedAt = 0
	.salt = 0
	.sessionID = 0
	.tempKeyExpiry = 0
	.sessionMux.Unlock()
}