package cat

import (
	"testing"

	"hamlog/internal/cat/civ"
)

// The Xiegu mode table is SHORTER than Icom's: LSB, USB, AM, CW, CWR and
// nothing else. The interesting cases are the ones with no equivalent — a
// digital mode must land on plain sideband rather than be refused, because
// refusing it would leave the rig on whatever it was and silently log the wrong
// mode.
func TestXieguModeByte(t *testing.T) {
	cases := []struct {
		mode string
		hz   int64
		want byte
		ok   bool
	}{
		{"SSB", 7150000, 0x00, true},  // LSB below 10 MHz
		{"SSB", 14250000, 0x01, true}, // USB above
		{"LSB", 14250000, 0x00, true}, // explicit beats the convention
		{"USB", 7150000, 0x01, true},
		{"AM", 7150000, 0x02, true},
		{"CW", 7030000, 0x03, true},
		{"CWR", 7030000, 0x07, true},
		{"FT8", 7074000, 0x00, true},  // no data mode on this rig → LSB
		{"FT8", 14074000, 0x01, true}, // → USB
		{"RTTY", 14080000, 0x01, true},
		{"FM", 145000000, 0x01, true}, // no FM either; sideband is the honest fallback
		{"", 14074000, 0x00, false},
	}
	for _, c := range cases {
		got, ok := xieguModeByte(c.mode, c.hz)
		if got != c.want || ok != c.ok {
			t.Errorf("xieguModeByte(%q, %d) = 0x%02X,%v — want 0x%02X,%v", c.mode, c.hz, got, ok, c.want, c.ok)
		}
	}
}

// The Xiegu mode bytes must decode through the shared Icom table, since that is
// the whole reason this backend reuses internal/cat/civ instead of its own
// codec. If the two ever disagree, the radio would be set to one mode and read
// back as another.
func TestXieguModesRoundTripThroughCIV(t *testing.T) {
	cases := []struct {
		mode string
		adif string
	}{
		// ADIF has no LSB/USB distinction — both sidebands ARE the SSB mode, and
		// that is what gets logged. The sideband still matters to the radio, which
		// is why xieguModeByte picks it from the frequency.
		{"LSB", "SSB"},
		{"USB", "SSB"},
		{"AM", "AM"},
		{"CW", "CW"},
	}
	for _, c := range cases {
		b, ok := xieguModeByte(c.mode, 14200000)
		if !ok {
			t.Fatalf("xieguModeByte(%q) refused", c.mode)
		}
		if got := civ.ModeToADIF(b, false); got != c.adif {
			t.Errorf("%s → 0x%02X → %q, want %q", c.mode, b, got, c.adif)
		}
	}
}

// Frequency encoding is shared with Icom, and it is the one field where a byte
// out of place mistunes the radio silently. Pinned here at the boundaries a
// Xiegu actually covers (it is an HF rig, so the 5-byte BCD upper bytes are 0).
func TestXieguFrequencyEncoding(t *testing.T) {
	for _, hz := range []int64{1840000, 7074000, 14074000, 28500000, 50313000} {
		b := civ.FreqToBCD(hz)
		if len(b) != 5 {
			t.Fatalf("FreqToBCD(%d) produced %d bytes, want 5", hz, len(b))
		}
		got, ok := civ.BCDToFreq(b)
		if !ok || got != hz {
			t.Errorf("round trip %d → % X → %d (ok=%v)", hz, b, got, ok)
		}
	}
}
