package ipmetagen

import (
	"bytes"
	"strings"
	"testing"
)

func TestGenerateEmbedsCountryCityAndASNMetadata(t *testing.T) {
	var out bytes.Buffer
	err := Generate(&out, GenerateOptions{
		PackageName: "ipmeta",
		CountryCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-DB1.CSV",
			Family: IPv4,
			Reader: strings.NewReader(strings.Join([]string{
				`"ip_from","ip_to","country_code","country_name"`,
				`"134744064","134744319","US","United States of America"`,
			}, "\n")),
		}},
		CityCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-DB3.CSV",
			Family: IPv4,
			Reader: strings.NewReader(strings.Join([]string{
				`"ip_from","ip_to","country_code","country_name","region_name","city_name"`,
				`"134744064","134744319","US","United States of America","California","Mountain View"`,
			}, "\n")),
		}},
		ASNCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-ASN.CSV",
			Family: IPv4,
			Reader: strings.NewReader(strings.Join([]string{
				`"ip_from","ip_to","cidr","asn","as"`,
				`"134744064","134744319","8.8.8.0/24","15169","Google LLC"`,
			}, "\n")),
		}},
	})
	if err != nil {
		t.Fatalf("generate: %v", err)
	}

	generated := out.String()
	for _, want := range []string{
		"package ipmeta",
		"Code generated by go run ./cmd/ipmeta-generate; DO NOT EDIT.",
		"var embeddedCountryIPv4StartData = \"\" +",
		`var embeddedCountryIPv4Codes = "" +`,
		`"US"`,
		"var embeddedCityRanges = []geoRange{",
		`first: netip.MustParseAddr("8.8.8.0")`,
		`CountryCode: "US"`,
		`Region: "California"`,
		`City: "Mountain View"`,
		`Provider: "Google LLC"`,
		`ASN: 15169`,
	} {
		if !strings.Contains(generated, want) {
			t.Fatalf("expected generated source to contain %q:\n%s", want, generated)
		}
	}
}

func TestGenerateAcceptsCountryOnlyDB1Rows(t *testing.T) {
	var out bytes.Buffer
	err := Generate(&out, GenerateOptions{
		PackageName: "ipmeta",
		CountryCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-DB1.CSV",
			Family: IPv4,
			Reader: strings.NewReader(`"134744064","134744319","US","United States of America"`),
		}},
	})
	if err != nil {
		t.Fatalf("generate: %v", err)
	}

	generated := out.String()
	if !strings.Contains(generated, `embeddedCountryIPv4Codes = "" +`) || !strings.Contains(generated, `"US"`) {
		t.Fatalf("expected country code in generated source:\n%s", generated)
	}
	if strings.Contains(generated, `City:`) || strings.Contains(generated, `Region:`) {
		t.Fatalf("country-only source should not invent city metadata:\n%s", generated)
	}
}

func TestGenerateRejectsMalformedRowsWithSourceContext(t *testing.T) {
	var out bytes.Buffer
	err := Generate(&out, GenerateOptions{
		PackageName: "ipmeta",
		CityCSVs: []CSVInput{{
			Name:   "bad-db3.csv",
			Family: IPv4,
			Reader: strings.NewReader(`"not-an-ip","134744319","US","United States of America","California","Mountain View"`),
		}},
	})
	if err == nil {
		t.Fatal("expected malformed import to fail")
	}
	if !strings.Contains(err.Error(), "bad-db3.csv") || !strings.Contains(err.Error(), "line 1") {
		t.Fatalf("expected source context in error, got %v", err)
	}
}

func TestGenerateMatchesIplocUnknownCountryFallback(t *testing.T) {
	var out bytes.Buffer
	err := Generate(&out, GenerateOptions{
		PackageName: "ipmeta",
		CountryCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-DB1.CSV",
			Family: IPv4,
			Reader: strings.NewReader(`"134744064","134744319","-","-"`),
		}},
	})
	if err != nil {
		t.Fatalf("generate: %v", err)
	}

	generated := out.String()
	if !strings.Contains(generated, `embeddedCountryIPv4Codes = "" +`) || !strings.Contains(generated, `"ZZ"`) {
		t.Fatalf("expected unknown DB1 country code to match iploc ZZ fallback:\n%s", generated)
	}
}

func TestGenerateCountryOnlyOmitsCityAndNetworkTables(t *testing.T) {
	var out bytes.Buffer
	err := Generate(&out, GenerateOptions{
		PackageName: "ipmeta",
		CountryOnly: true,
		CountryCSVs: []CSVInput{{
			Name:   "IP2LOCATION-LITE-DB1.CSV",
			Family: IPv4,
			Reader: strings.NewReader(`"134744064","134744319","US","United States of America"`),
		}},
	})
	if err != nil {
		t.Fatalf("generate: %v", err)
	}

	generated := out.String()
	for _, want := range []string{"embeddedCountryIPv4StartData", `embeddedCountryIPv4Codes = "" +`, `"US"`} {
		if !strings.Contains(generated, want) {
			t.Fatalf("expected country-only generated source to contain %q:\n%s", want, generated)
		}
	}
	for _, notWant := range []string{"embeddedCityRanges", "embeddedNetworkRanges"} {
		if strings.Contains(generated, notWant) {
			t.Fatalf("country-only generated source should not contain %q:\n%s", notWant, generated)
		}
	}
}
