// Copyright 2024 XDC Network
// XDC P2P broadcast functions for consensus messages.
// Ports BroadcastVote/BroadcastTimeout/BroadcastSyncInfo from v2.6.8
// (XDPoSChain/eth/handler.go BroadcastVote/Timeout/SyncInfo +
// peer.go SendVote/Timeout/SyncInfo).

package eth

import (
	"github.com/ethereum/go-ethereum/core/types"
	"github.com/ethereum/go-ethereum/eth/protocols/eth"
	"github.com/ethereum/go-ethereum/log"
	"github.com/ethereum/go-ethereum/rlp"
)

// BroadcastVote propagates a V2 consensus vote to all connected peers.
// Matches XDPoSChain/eth/handler.go BroadcastVote(): RLP-encode the vote
// once, then p2p.Send(VoteMsg, payload) to each peer via the per-peer
// Send wrapper (which calls p2p.Send under the hood).
func (h *handler) BroadcastVote(vote *types.Vote) {
	if vote == nil {
		return
	}
	payload, err := rlp.EncodeToBytes(vote)
	if err != nil {
		log.Error("[XDC-P2P] Failed to encode vote", "err", err)
		return
	}
	h.peers.lock.RLock()
	peers := make([]*ethPeer, 0, len(h.peers.peers))
	for _, p := range h.peers.peers {
		peers = append(peers, p)
	}
	h.peers.lock.RUnlock()

	pkt := &eth.VotePacket{Vote: payload}
	for _, p := range peers {
		if err := p.Peer.Send(eth.VoteMsg, pkt); err != nil {
			log.Trace("[XDC-P2P] Send vote failed", "peer", p.ID(), "err", err)
			continue
		}
	}
	log.Debug("[XDC-P2P] Vote broadcast complete", "peers", len(peers), "round", vote.ProposedBlockInfo.Round)
}

// BroadcastTimeout propagates a V2 consensus timeout to all connected peers.
// Matches XDPoSChain/eth/handler.go BroadcastTimeout().
func (h *handler) BroadcastTimeout(timeout *types.Timeout) {
	if timeout == nil {
		return
	}
	payload, err := rlp.EncodeToBytes(timeout)
	if err != nil {
		log.Error("[XDC-P2P] Failed to encode timeout", "err", err)
		return
	}
	h.peers.lock.RLock()
	peers := make([]*ethPeer, 0, len(h.peers.peers))
	for _, p := range h.peers.peers {
		peers = append(peers, p)
	}
	h.peers.lock.RUnlock()

	pkt := &eth.TimeoutPacket{Timeout: payload}
	for _, p := range peers {
		if err := p.Peer.Send(eth.TimeoutMsg, pkt); err != nil {
			log.Trace("[XDC-P2P] Send timeout failed", "peer", p.ID(), "err", err)
			continue
		}
	}
	log.Debug("[XDC-P2P] Timeout broadcast complete", "peers", len(peers), "round", timeout.Round)
}

// BroadcastSyncInfo propagates V2 sync info to all connected peers.
// Matches XDPoSChain/eth/handler.go BroadcastSyncInfo().
func (h *handler) BroadcastSyncInfo(syncInfo *types.SyncInfo) {
	if syncInfo == nil {
		return
	}
	payload, err := rlp.EncodeToBytes(syncInfo)
	if err != nil {
		log.Error("[XDC-P2P] Failed to encode syncInfo", "err", err)
		return
	}
	h.peers.lock.RLock()
	peers := make([]*ethPeer, 0, len(h.peers.peers))
	for _, p := range h.peers.peers {
		peers = append(peers, p)
	}
	h.peers.lock.RUnlock()

	pkt := &eth.SyncInfoPacket{SyncInfo: payload}
	for _, p := range peers {
		if err := p.Peer.Send(eth.SyncInfoMsg, pkt); err != nil {
			log.Trace("[XDC-P2P] Send syncInfo failed", "peer", p.ID(), "err", err)
			continue
		}
	}
	log.Debug("[XDC-P2P] SyncInfo broadcast complete", "peers", len(peers))
}
