package cat

import "testing"

// In split, OpsLog stays on the RECEIVE slice.
//
// SmartSDR moves its "active" flag onto the TX slice as soon as the transmit
// frequency is touched. Following it hands the operator the S-meter, audio
// level, filter and DSP of a receiver they are not listening to — while the DX
// they are working is on the other slice.
func TestMainSliceStaysOnRXInSplit(t *testing.T) {
	mk := func(hz int64, mode string, active, tx bool) *flexSlice {
		return &flexSlice{freqHz: hz, mode: mode, active: active, tx: tx, inUse: true}
	}

	// Working a DX on 14.100, transmitting up on 14.200. The radio has focused
	// the transmitter.
	f := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{
		0: mk(14_100_000, "USB", false, false), // where the DX is heard
		1: mk(14_200_000, "USB", true, true),   // where we transmit, radio-focused
	}}
	idx, s := f.mainSliceLocked()
	if idx != 0 || s == nil || s.freqHz != 14_100_000 {
		t.Errorf("main slice = %d (%v Hz) — want slice 0, the RX side on 14.100", idx, s.freqHz)
	}

	// Simplex: the radio's focus is authoritative again, nothing to prefer.
	f2 := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{
		0: mk(14_100_000, "USB", false, false),
		1: mk(14_200_000, "USB", true, true),
	}}
	f2.slices[0].inUse = false // only the TX slice is in use → simplex
	if idx, _ := f2.mainSliceLocked(); idx != 1 {
		t.Errorf("simplex main slice = %d, want 1 — the only slice in use", idx)
	}

	// Two same-band slices in DIFFERENT classes are not a split (SSB + FT8), so
	// there is nothing to prefer and the radio's focus stands.
	f3 := &Flex{pinnedSlice: -1, slices: map[int]*flexSlice{
		0: mk(14_074_000, "DIGU", false, false),
		1: mk(14_200_000, "USB", true, true),
	}}
	if idx, _ := f3.mainSliceLocked(); idx != 1 {
		t.Errorf("SSB+FT8 main slice = %d, want 1 — that is not a split", idx)
	}
}

// A slice picked IN OPSLOG wins over everything, including the split rule and
// the radio's own focus. Picking one on the radio does not move OpsLog.
func TestPinnedSliceWins(t *testing.T) {
	mk := func(hz int64, mode string, active, tx bool) *flexSlice {
		return &flexSlice{freqHz: hz, mode: mode, active: active, tx: tx, inUse: true}
	}
	f := &Flex{pinnedSlice: 1, slices: map[int]*flexSlice{
		0: mk(14_100_000, "USB", true, false), // radio-focused
		1: mk(14_200_000, "USB", false, true), // chosen in OpsLog
	}}
	if idx, _ := f.mainSliceLocked(); idx != 1 {
		t.Errorf("main slice = %d — an explicit choice in OpsLog must win", idx)
	}

	// A pin on a slice that is no longer in use is not a choice any more: it
	// must not strand OpsLog on a receiver that has been closed.
	f.slices[1].inUse = false
	if idx, _ := f.mainSliceLocked(); idx != 0 {
		t.Errorf("main slice = %d — a closed slice cannot stay pinned", idx)
	}
}
