package udp

import (
	"net"
	"testing"
	"time"
)

// The relay exists so a second application can be fed the same WSJT-X stream,
// and the ONE thing it must get right is that the bytes are unchanged. The
// relays in the field prepend an origin header ("127.0.0.1:2237|") — which is
// why stripForwarderHeader had to be written on the receiving side — so a
// header here would inflict on the next program the fault we had to survive.
func TestRelayForwardsVerbatim(t *testing.T) {
	dst, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
	if err != nil {
		t.Fatal(err)
	}
	defer dst.Close()
	port := dst.LocalAddr().(*net.UDPAddr).Port

	m := &Manager{outbound: []Config{{
		ID: 1, Name: "relay", ServiceType: ServiceWSJTRelay,
		DestinationIP: "127.0.0.1", Port: port,
	}}}

	// A packet with bytes that no parser here understands, on purpose: the relay
	// must not care what it is carrying.
	sent := []byte{0xad, 0xbc, 0xcb, 0xda, 0x00, 0x00, 0x00, 0x63, 0xde, 0xad, 0xbe, 0xef}
	m.RelayInbound(sent, 2237)

	buf := make([]byte, 1024)
	_ = dst.SetReadDeadline(time.Now().Add(2 * time.Second))
	n, _, err := dst.ReadFromUDP(buf)
	if err != nil {
		t.Fatalf("nothing relayed: %v", err)
	}
	if got := buf[:n]; string(got) != string(sent) {
		t.Errorf("relayed % X, want % X — the bytes must go out unchanged", got, sent)
	}
}

// A relay aimed at one of OpsLog's OWN listening ports would come straight back
// in, be relayed again, and saturate the loopback within seconds. The row is
// skipped instead.
func TestRelayRefusesToFeedItself(t *testing.T) {
	own, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
	if err != nil {
		t.Fatal(err)
	}
	defer own.Close()
	port := own.LocalAddr().(*net.UDPAddr).Port

	m := &Manager{
		inbound: map[int64]*Server{
			7: {cfg: Config{ID: 7, Port: port, ServiceType: ServiceWSJT}},
		},
		outbound: []Config{{
			ID: 1, Name: "loop", ServiceType: ServiceWSJTRelay,
			DestinationIP: "127.0.0.1", Port: port,
		}},
	}
	m.RelayInbound([]byte{1, 2, 3, 4}, 2237)

	buf := make([]byte, 64)
	_ = own.SetReadDeadline(time.Now().Add(300 * time.Millisecond))
	if n, _, err := own.ReadFromUDP(buf); err == nil {
		t.Fatalf("relayed %d bytes back into our own listener — that is the loop", n)
	}
}

// No relay rows configured must cost nothing and send nothing.
func TestRelayWithNoRowsIsSilent(t *testing.T) {
	m := &Manager{}
	m.RelayInbound([]byte{1, 2, 3}, 2237) // must not panic
	m.RelayInbound(nil, 2237)
}
