package main

import (
	"testing"
	"time"

	"hamlog/internal/bandopen"
	"hamlog/internal/cluster"
)

// The "Watch for band openings" switch has to gate the DETECTOR, not just the
// extra data sources.
//
// It originally governed only the RBN nodes and the PSK Reporter feed, while
// the detector itself ran on every ordinary cluster spot — so an operator who
// had never enabled the watch still got opening banners for a feature he had
// deliberately left off. That is what this pins.
func TestBandOpenWatchGatesTheDetector(t *testing.T) {
	spot := func() cluster.Spot {
		return cluster.Spot{
			DXCall: "EA1ABC", Band: "6m", DistanceKm: 1400, ShortPath: 210,
			ReceivedAt: time.Now(),
		}
	}

	// Switched off: the spot must not even reach the detector.
	off := &App{opSet: true, opLat: 48.0, opLon: 2.0}
	off.detectBandOpening(spot())
	if off.bandOpen.det != nil {
		t.Error("the detector ran with the watch switched off")
	}

	// Switched on: the same spot is accepted (one spot is not an opening, so
	// nothing is announced — but the detector now exists and is collecting).
	on := &App{opSet: true, opLat: 48.0, opLon: 2.0}
	on.bandOpen.on.Store(true)
	on.detectBandOpening(spot())
	if on.bandOpen.det == nil {
		t.Error("the detector did not run with the watch switched on")
	}
}

// Switching the watch off must put the badges out. They fade on a timer fed by
// spots the detector no longer looks at, so left alone they would stay lit
// until the next restart.
func TestClearBandOpeningsPutsTheBadgesOut(t *testing.T) {
	a := &App{}
	a.bandOpen.live = map[string]bandopen.Opening{"6m": {Band: "6m", Calls: 9}}
	a.bandOpen.aliveUntil = map[string]time.Time{"6m": time.Now().Add(time.Hour)}
	a.bandOpen.det = bandopen.New(bandopen.DefaultConfig())
	a.bandOpen.last = []bandopen.Opening{{Band: "6m", Calls: 9}}

	a.clearBandOpenings()

	if got := a.GetLiveOpenings(); len(got) != 0 {
		t.Errorf("a badge stayed lit after the watch was switched off: %v", got)
	}
	if a.bandOpen.det != nil {
		t.Error("the accumulated spot window survived — switching back on would start from a stale burst")
	}
	// The history is NOT cleared: those openings really happened.
	if len(a.GetBandOpenings()) != 1 {
		t.Error("the remembered openings were thrown away")
	}
}

// Unticking a band in Settings must actually stop its announcements.
//
// Nothing checked the operator's selection on either feed path: bandopen.Watched
// only says which bands the detector is CAPABLE of. So a station with just 6 m
// ticked still got 10 m and 2 m badges, from the cluster path and — once grid
// chasing widened the subscription to every band — from PSK Reporter too.
func TestBandOpenHonoursTheSelectedBands(t *testing.T) {
	a := &App{opSet: true, opLat: 48, opLon: 2}
	a.bandOpen.on.Store(true)
	a.setBandOpenBands([]string{"6m"})

	if !a.bandOpenWanted("6m") {
		t.Error("6m is ticked and was refused")
	}
	for _, b := range []string{"10m", "2m", "4m"} {
		if a.bandOpenWanted(b) {
			t.Errorf("%s is not ticked and was accepted", b)
		}
	}
	// A band the detector cannot watch at all stays out whatever is stored.
	if a.bandOpenWanted("20m") {
		t.Error("20m is not a watched band and was accepted")
	}

	// And the cluster path must obey it too.
	a.detectBandOpening(cluster.Spot{
		DXCall: "K1ABC", Band: "10m", DistanceKm: 6000, ShortPath: 280, ReceivedAt: time.Now(),
	})
	if a.bandOpen.det != nil {
		t.Error("a spot on an unticked band reached the detector")
	}
}

// Unticking a band puts its badge out. They fade on a timer fed by spots the
// detector no longer looks at, so it would otherwise stay lit until a restart.
func TestUntickingABandClearsItsBadge(t *testing.T) {
	a := &App{}
	a.bandOpen.live = map[string]bandopen.Opening{
		"6m":  {Band: "6m", Calls: 9},
		"10m": {Band: "10m", Calls: 5},
	}
	a.bandOpen.aliveUntil = map[string]time.Time{
		"6m":  time.Now().Add(time.Hour),
		"10m": time.Now().Add(time.Hour),
	}
	a.setBandOpenBands([]string{"6m"})

	live := a.GetLiveOpenings()
	if len(live) != 1 || live[0].Band != "6m" {
		t.Errorf("live openings = %v, want only 6m", live)
	}
}
