package peer

import (
	"log"
	"net"
	"sync/atomic"
	"time"
)

func runMCReader(
	rt *atomic.Pointer[routingTable],
	handleControlMsg func(destIP byte, msg any),
) {
	for {
		runMCReaderInner(rt, handleControlMsg)
		time.Sleep(broadcastErrorTimeoutInterval)
	}
}

func runMCReaderInner(
	rt *atomic.Pointer[routingTable],
	handleControlMsg func(destIP byte, msg any),
) {
	var (
		raw  = newBuf()
		buf  = newBuf()
		logf = func(s string, args ...any) {
			log.Printf("[MCReader] "+s, args...)
		}
	)

	conn, err := net.ListenMulticastUDP("udp", nil, multicastAddr)
	if err != nil {
		logf("Failed to bind to multicast address: %v", err)
		return
	}

	for {
		conn.SetReadDeadline(time.Now().Add(32 * time.Second))
		n, remoteAddr, err := conn.ReadFromUDPAddrPort(raw[:bufferSize])
		if err != nil {
			logf("Failed to read from UDP port): %v", err)
			return
		}

		raw = raw[:n]
		h, ok := headerFromLocalDiscoveryPacket(raw)
		if !ok {
			logf("Failed to open discovery packet?")
			continue
		}

		peer := rt.Load().Peers[h.SourceIP]
		if peer.PubSignKey == nil {
			logf("No signing key for peer %d.", h.SourceIP)
			continue
		}

		if !verifyLocalDiscoveryPacket(raw, buf, peer.PubSignKey) {
			logf("Invalid signature from peer: %d", h.SourceIP)
			continue
		}

		msg := controlMsg[packetLocalDiscovery]{
			SrcIP:   h.SourceIP,
			SrcAddr: remoteAddr,
		}
		logf("Got discovery packet from peer %d.", h.SourceIP)
		handleControlMsg(h.SourceIP, msg)
	}
}
