package udp

import (
	"bytes"
	"encoding/binary"
	"testing"
)

// A grid reaches OpsLog in TWO kinds of message, not one. The reply that
// answers a CQ with a locator — "C91RU IZ5EME JN52" — is the commonest of them
// on a busy band, and reading only CQs meant any station whose CQ we happened
// to miss had no known grid at all, so it could never be flagged as a new one.
func TestDecodeGridFromBothMessageShapes(t *testing.T) {
	for _, tc := range []struct {
		msg  string
		call string
		cq   bool
		grid string
		why  string
	}{
		{"CQ RW9MZ MO74", "RW9MZ", true, "MO74", "a plain CQ"},
		{"CQ DX F4BPO JN36", "F4BPO", true, "JN36", "a CQ with a modifier"},
		{"C91RU IZ5EME JN52", "IZ5EME", false, "JN52", "a reply answering with its grid"},
		{"YB1EWD YO6GLT KN36", "YO6GLT", false, "KN36", "the same, other way round"},

		// Everything else in the third slot is a report or a sign-off, and must
		// never be mistaken for a locator.
		{"C91RU IZ5EME -05", "IZ5EME", false, "", "a signal report is not a grid"},
		{"C91RU IZ5EME R-05", "IZ5EME", false, "", "a rogered report is not a grid"},
		{"C91RU IZ5EME RRR", "IZ5EME", false, "", "RRR is not a grid"},
		{"C91RU IZ5EME RR73", "IZ5EME", false, "", "RR73 has the shape of one and is not"},
		{"C91RU IZ5EME 73", "IZ5EME", false, "", "73 is not a grid"},
		{"<YO7LBX> 8F81SU RR73", "8F81SU", false, "", "a hashed call, signing off"},
	} {
		call, cq, grid := wsjtSender(tc.msg)
		if call != tc.call || cq != tc.cq || grid != tc.grid {
			t.Errorf("wsjtSender(%q) = (%q, %v, %q), want (%q, %v, %q) — %s",
				tc.msg, call, cq, grid, tc.call, tc.cq, tc.grid, tc.why)
		}
	}
}

// The Reply replays the decode field for field, so the message must survive the
// trip UNTRIMMED. DecodeMsg is trimmed for display; DecodeMsgRaw is what goes
// back, and a stripped trailing space is a mismatch the far end reports nowhere.
func TestDecodeKeepsTheUntrimmedMessage(t *testing.T) {
	qstr := func(b *bytes.Buffer, v string) {
		binary.Write(b, binary.BigEndian, int32(len(v)))
		b.WriteString(v)
	}
	const padded = "CQ RW9MZ MO74  "
	var p bytes.Buffer
	binary.Write(&p, binary.BigEndian, uint32(wsjtMagic))
	binary.Write(&p, binary.BigEndian, uint32(2))
	binary.Write(&p, binary.BigEndian, uint32(wsjtMsgDecode))
	qstr(&p, "JTDX")
	binary.Write(&p, binary.BigEndian, uint8(1))
	binary.Write(&p, binary.BigEndian, uint32(45_000_000))
	binary.Write(&p, binary.BigEndian, int32(-6))
	binary.Write(&p, binary.BigEndian, float64(0.2))
	binary.Write(&p, binary.BigEndian, uint32(1500))
	qstr(&p, "~")
	qstr(&p, padded)

	ev, ok, err := ParseWSJT(p.Bytes())
	if err != nil || !ok {
		t.Fatalf("parse: %v ok=%v", err, ok)
	}
	if ev.DecodeMsgRaw != padded {
		t.Errorf("DecodeMsgRaw = %q, want %q — a Reply built from this will not match", ev.DecodeMsgRaw, padded)
	}
	if ev.DecodeMsg != "CQ RW9MZ MO74" {
		t.Errorf("DecodeMsg = %q, want it trimmed for display", ev.DecodeMsg)
	}
}
