package cluster

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

// A quiet cluster must not be treated as a broken one.
//
// Reported by an operator whose node sends little: nothing for two minutes and
// OpsLog reconnected — losing the login, the filters, and any spot that landed
// during the gap. The read deadline was being read as a verdict on the link
// rather than as a way to stay responsive to a stop request.
//
// The test holds the connection open, silent for longer than one deadline, then
// sends a spot. A session that survives receives it; one that reconnects does
// not, because this listener never accepts twice.
func TestSilenceDoesNotEndTheSession(t *testing.T) {
	// Shorten the tick so the test exercises the real code path in seconds.
	defer func(orig time.Duration) { idleTick = orig }(idleTick)
	idleTick = time.Second
	ln, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	defer ln.Close()

	accepted := make(chan net.Conn, 2)
	go func() {
		for {
			c, err := ln.Accept()
			if err != nil {
				return
			}
			accepted <- c
		}
	}()

	host, portStr, _ := net.SplitHostPort(ln.Addr().String())
	port, err := strconv.Atoi(portStr)
	if err != nil {
		t.Fatal(err)
	}

	spots := make(chan Spot, 4)
	s := &session{
		cfg:      ServerConfig{Name: "quiet", Host: host, Port: port},
		onSpot:   func(sp Spot) { spots <- sp },
		onLine:   func(Line) {},
		onStatus: func() {},
		stopCh:   make(chan struct{}),
	}

	done := make(chan error, 1)
	go func() { _, err := s.runOnce(); done <- err }()

	conn := <-accepted
	defer conn.Close()

	// Silent for longer than one deadline: the loop must ride through it.
	time.Sleep(3 * idleTick)

	select {
	case c := <-accepted:
		c.Close()
		t.Fatal("the session reconnected during the silence")
	case err := <-done:
		t.Fatalf("the session ended during the silence: %v", err)
	default:
	}

	// Now a spot: it proves the ORIGINAL connection is still the live one.
	if _, err := conn.Write([]byte("DX de F4BPO:     14074.0  OY1CT        FT8            1234Z\r\n")); err != nil {
		t.Fatal(err)
	}
	select {
	case sp := <-spots:
		if sp.DXCall != "OY1CT" {
			t.Errorf("spot from the wrong station: %+v", sp)
		}
	case <-time.After(5 * time.Second):
		t.Fatal("the spot sent after the silence never arrived")
	}

	close(s.stopCh)
	<-done
}
