package qso

import "testing"

// baseCall picks the operator's OWN callsign out of a portable form. The slash
// carries a qualifier on either side and which side depends on what it is, so
// this is the whole difficulty.
func TestBaseCall(t *testing.T) {
	for in, want := range map[string]string{
		"RK3DWA":      "RK3DWA",
		"RK3DWA/3":    "RK3DWA", // call-area digit
		"RK3DWA/P":    "RK3DWA", // portable
		"RK3DWA/QRP":  "RK3DWA",
		"RK3DWA/MM":   "RK3DWA",
		"ZA/OE8NDR":   "OE8NDR", // an Austrian in Albania — the case that prompted this
		"ZA/IZ2DPX":   "IZ2DPX",
		"F/DL1ABC":    "DL1ABC",
		"F/DL1ABC/P":  "DL1ABC",
		"KH6/K6ABC":   "K6ABC",
		"VP2E/W1ABC":  "W1ABC",
		"3DA0/ZS1ABC": "ZS1ABC",
		"9A/S51AB":    "S51AB",
		"/RK3DWA":     "RK3DWA",
	} {
		if got := baseCall(in); got != want {
			t.Errorf("baseCall(%q) = %q, want %q", in, got, want)
		}
	}
}

// The predicate behind "Worked before". Exact when folding is off; with it on,
// a station's portable forms are one operator — and the fold has to work from
// either end, because you may type the base call or the portable one.
func TestCallMatch(t *testing.T) {
	if pred, args := callMatch("RK3DWA", false); pred != "callsign = ?" || len(args) != 1 || args[0] != "RK3DWA" {
		t.Errorf("exact: got %q %v", pred, args)
	}

	// Typing the base call: match it, everything suffixed off it, and every
	// prefixed form of it.
	_, args := callMatch("RK3DWA", true)
	want := []any{"RK3DWA", "RK3DWA/%", "%/RK3DWA", "%/RK3DWA/%"}
	assertArgs(t, "base call", args, want)

	// Typing a portable form must reach the plain call too — the qualifier is
	// stripped from the INPUT, not just matched in the column.
	_, args = callMatch("RK3DWA/3", true)
	assertArgs(t, "portable input", args, want)
}

// A prefixed call is the same operator, and NOT every other visitor to that
// country.
//
// Matching on the part before the slash made ZA/OE8NDR the station "ZA", so the
// worked-before list for one Austrian operating from Albania showed every other
// ZA/ guest — two Italians — and counted them as four contacts "with this
// call". Reported from a screenshot of exactly that.
func TestCallMatchPrefixedIsTheOperatorNotTheCountry(t *testing.T) {
	_, args := callMatch("ZA/OE8NDR", true)
	assertArgs(t, "ZA/OE8NDR", args, []any{"OE8NDR", "OE8NDR/%", "%/OE8NDR", "%/OE8NDR/%"})

	for _, a := range args {
		if s, _ := a.(string); s == "ZA" || s == "ZA/%" {
			t.Fatalf("the country prefix is still being matched as a station: %v", args)
		}
	}

	// And the two are not each other: nothing in one operator's predicate can
	// select the other's call.
	_, other := callMatch("ZA/IZ2DPX", true)
	assertArgs(t, "ZA/IZ2DPX", other, []any{"IZ2DPX", "IZ2DPX/%", "%/IZ2DPX", "%/IZ2DPX/%"})
}

// A base too short to be a callsign falls back to an exact match. "F/DL1ABC"
// resolves fine, but a malformed entry must never produce a LIKE that selects
// half the logbook.
func TestCallMatchRefusesAShortBase(t *testing.T) {
	for _, call := range []string{"F/", "9A", "/P", "K/M"} {
		pred, args := callMatch(call, true)
		if pred != "callsign = ?" || len(args) != 1 {
			t.Errorf("%q produced %q %v — want an exact match", call, pred, args)
		}
	}
}

func assertArgs(t *testing.T, what string, got, want []any) {
	t.Helper()
	if len(got) != len(want) {
		t.Fatalf("%s: args %v, want %v", what, got, want)
	}
	for i := range want {
		if got[i] != want[i] {
			t.Fatalf("%s: args %v, want %v", what, got, want)
		}
	}
}
