package lookup

import "testing"

// fakeDXCC resolves a handful of calls, enough to stand in for cty.dat.
type fakeDXCC map[string]struct {
	num       int
	country   string
	cont      string
	cqz, ituz int
	lat, lon  float64
}

func (f fakeDXCC) Resolve(call string) (int, string, string, int, int, float64, float64, bool) {
	e, ok := f[call]
	if !ok {
		return 0, "", "", 0, 0, 0, 0, false
	}
	return e.num, e.country, e.cont, e.cqz, e.ituz, e.lat, e.lon, true
}

func testDXCC() fakeDXCC {
	return fakeDXCC{
		// Costa Rica, as cty.dat reads the OPERATING call.
		"TI8/W2RE": {num: 308, country: "Costa Rica", cont: "NA", cqz: 7, ituz: 11, lat: 9.9, lon: -84.1},
		// The home call: United States.
		"W2RE": {num: 291, country: "United States", cont: "NA", cqz: 5, ituz: 8, lat: 39.8, lon: -98.5},
		// A same-entity portable: still France either way.
		"F4BPO/P": {num: 227, country: "France", cont: "EU", cqz: 14, ituz: 27, lat: 46.2, lon: 2.2},
		"F4BPO":   {num: 227, country: "France", cont: "EU", cqz: 14, ituz: 27, lat: 46.2, lon: 2.2},
	}
}

// A callbook record for a portable call routinely carries the operator's HOME
// address — most QRZ pages for a portable call do — and a subdivision belongs to
// an entity. Carrying the home county across an entity change is not cosmetic:
// CNTY is defined as a US county, so TI8/W2RE was coming out as a Costa Rica
// contact credited to Dutchess County, New York, with the distance and beam
// heading taken from a square 3,600 km from where the station actually was.
func TestPortableInAnotherEntityDropsTheHomeSubdivision(t *testing.T) {
	r := Result{
		Callsign: "TI8/W2RE",
		Name:     "Raymond", // who they are — kept
		QTH:      "Poughquag",
		Address:  "499 Pleasant Ridge Road", // cards still go there — kept
		State:    "NY",
		County:   "Dutchess",
		Grid:     "FN31",
		Lat:      41.6, Lon: -73.7,
		DXCC: 291,
	}
	fillFromDXCC(&r, testDXCC())

	if r.County != "" {
		t.Errorf("county = %q, want empty — a US county on a Costa Rica QSO is a false award credit", r.County)
	}
	if r.State != "" {
		t.Errorf("state = %q, want empty — a subdivision of the entity that is not being worked", r.State)
	}
	if r.Grid != "" {
		t.Errorf("grid = %q, want empty — it is the home square, 3,600 km from the operation", r.Grid)
	}
	// The entity and its centroid take over, so distance and bearing mean
	// something again.
	if r.DXCC != 308 || r.Country != "Costa Rica" {
		t.Errorf("entity = %d %q, want 308 Costa Rica", r.DXCC, r.Country)
	}
	if r.Lat != 9.9 || r.Lon != -84.1 {
		t.Errorf("lat/lon = %v/%v, want the Costa Rica centroid — the home coordinates must not survive", r.Lat, r.Lon)
	}
	// Who they are, and where their cards go, is unchanged.
	if r.Name != "Raymond" || r.Address != "499 Pleasant Ridge Road" {
		t.Errorf("name/address were cleared (%q / %q) — a portable operator's post still reaches home", r.Name, r.Address)
	}
}

// The other half of the rule: a portable WITHIN the same entity is at home as
// far as the entity is concerned, and its details must survive untouched.
func TestSameEntityPortableKeepsItsLocation(t *testing.T) {
	r := Result{
		Callsign: "F4BPO/P",
		State:    "77", County: "Seine-et-Marne", Grid: "JN18cs",
		Lat: 48.8, Lon: 2.4, DXCC: 227,
	}
	fillFromDXCC(&r, testDXCC())

	if r.Grid != "JN18cs" || r.County != "Seine-et-Marne" || r.State != "77" {
		t.Errorf("a same-entity portable lost its location: grid=%q county=%q state=%q", r.Grid, r.County, r.State)
	}
	if r.Lat != 48.8 || r.Lon != 2.4 {
		t.Errorf("lat/lon = %v/%v — the precise home position was replaced by the entity centroid", r.Lat, r.Lon)
	}
}

// The other half again, and the one an operator reported: a compound call with
// a callbook page OF ITS OWN. QRZ files HP/WE9G under that exact form, with the
// Panama address and square the station is actually operating from — and the
// QSO was being logged with no grid at all while the page plainly showed one.
func TestACompoundCallWithItsOwnPageKeepsThatPagesLocation(t *testing.T) {
	dxcc := testDXCC()
	dxcc["HP/WE9G"] = struct {
		num       int
		country   string
		cont      string
		cqz, ituz int
		lat, lon  float64
	}{num: 88, country: "Panama", cont: "NA", cqz: 7, ituz: 11, lat: 8.5, lon: -80.0}
	dxcc["WE9G"] = struct {
		num       int
		country   string
		cont      string
		cqz, ituz int
		lat, lon  float64
	}{num: 291, country: "United States", cont: "NA", cqz: 5, ituz: 8, lat: 39.8, lon: -98.5}

	r := Result{
		Callsign: "HP/WE9G",
		Name:     "Richard B",
		Country:  "Panama", // the RECORD's own country: this page is the operation
		Grid:     "EJ98xq",
		Lat:      8.686667, Lon: -80.043333,
	}
	fillFromDXCC(&r, dxcc)

	if r.Grid != "EJ98xq" {
		t.Errorf("grid = %q, want EJ98xq — the page describes the operation, not a home address", r.Grid)
	}
	if r.Lat != 8.686667 || r.Lon != -80.043333 {
		t.Errorf("lat/lon = %v/%v — the station's own position was replaced by the entity centroid", r.Lat, r.Lon)
	}
}

func TestSameEntityNameAcrossVocabularies(t *testing.T) {
	same := [][2]string{
		{"Germany", "Fed. Rep. of Germany"},
		{"United States", "United States of America"},
		{"Panama", "Panama"},
		{"Kosovo", "Republic of Kosovo"},
	}
	for _, p := range same {
		if !sameEntityName(p[0], p[1]) {
			t.Errorf("%q and %q read as different entities", p[0], p[1])
		}
	}
	for _, p := range [][2]string{{"Costa Rica", "United States"}, {"France", "Belgium"}, {"", "Panama"}} {
		if sameEntityName(p[0], p[1]) {
			t.Errorf("%q and %q read as the same entity", p[0], p[1])
		}
	}
}
