package udp

import (
	"strings"
	"testing"
)

// A representative N1MM+ <contactinfo> datagram (trimmed to the fields we
// read). rxfreq 1402500 tens-of-Hz == 14.025 MHz → 20m.
const sampleContactInfo = `<?xml version="1.0" encoding="utf-8"?>
<contactinfo>
  <contestname>DX</contestname>
  <timestamp>2024-03-15 14:25:30</timestamp>
  <mycall>K1ABC</mycall>
  <band>14</band>
  <rxfreq>1402500</rxfreq>
  <txfreq>1402500</txfreq>
  <operator>K1ABC</operator>
  <mode>CW</mode>
  <call>VE9AA</call>
  <snt>599</snt>
  <sntnr>1</sntnr>
  <rcv>599</rcv>
  <rcvnr>42</rcvnr>
  <gridsquare>FN65</gridsquare>
  <name>Mike</name>
  <comment>tnx</comment>
  <power>100</power>
</contactinfo>`

func TestParseN1MMContactInfo(t *testing.T) {
	adif, ok, err := ParseN1MM([]byte(sampleContactInfo))
	if err != nil {
		t.Fatalf("ParseN1MM error: %v", err)
	}
	if !ok {
		t.Fatal("expected a loggable contact, got ok=false")
	}
	want := map[string]string{
		"<call:5>VE9AA":        "callsign",
		"<qso_date:8>20240315": "date",
		"<time_on:6>142530":    "time",
		"<band:3>20m":          "band",
		"<mode:2>CW":           "mode",
		"<freq:9>14.025000":    "freq",
		"<rst_sent:3>599":      "rst sent",
		"<rst_rcvd:3>599":      "rst rcvd",
		"<gridsquare:4>FN65":   "grid",
		"<name:4>Mike":         "name",
		"<stx:1>1":             "stx serial",
		"<srx:2>42":            "srx serial",
		"<eor>":                "terminator",
	}
	for sub, label := range want {
		if !strings.Contains(adif, sub) {
			t.Errorf("missing %s field %q in:\n%s", label, sub, adif)
		}
	}
}

func TestParseN1MMSSBMapping(t *testing.T) {
	pkt := `<contactinfo><call>F4XYZ</call><mode>USB</mode><band>14</band><rxfreq>1420000</rxfreq><timestamp>2024-01-01 00:00:00</timestamp></contactinfo>`
	adif, ok, err := ParseN1MM([]byte(pkt))
	if err != nil || !ok {
		t.Fatalf("ParseN1MM ok=%v err=%v", ok, err)
	}
	if !strings.Contains(adif, "<mode:3>SSB") {
		t.Errorf("USB should map to SSB, got:\n%s", adif)
	}
}

func TestParseN1MMIgnoresNonContacts(t *testing.T) {
	for _, pkt := range []string{
		`<RadioInfo><app>N1MM</app><freq>1402500</freq></RadioInfo>`,
		`<spot><dxcall>VE9AA</dxcall><frequency>14025</frequency></spot>`,
		`<contactdelete><call>VE9AA</call></contactdelete>`,
	} {
		_, ok, err := ParseN1MM([]byte(pkt))
		if err != nil {
			t.Errorf("unexpected error for %q: %v", pkt, err)
		}
		if ok {
			t.Errorf("expected ok=false (ignored) for %q", pkt)
		}
	}
}

func TestBandFromHz(t *testing.T) {
	cases := map[int64]string{
		14_025_000:  "20m",
		7_100_000:   "40m",
		3_650_000:   "80m",
		28_400_000:  "10m",
		144_200_000: "2m",
		0:           "",
		15_000_000:  "", // between 20m and 17m → no band
	}
	for hz, want := range cases {
		if got := bandFromHz(hz); got != want {
			t.Errorf("bandFromHz(%d) = %q, want %q", hz, got, want)
		}
	}
}
