package nettool

import (
	"net/netip"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	// Test that MultiURL is comparable.
	_ map[MultiURL]struct{} = nil
)

func TestNewMultiURLForHost(t *testing.T) {
	assert.PanicsWithValue(t, emptySchemePanicMsg, func() {
		NewMultiURLForHost("", "localhost", "", 123)
	})
	assert.PanicsWithValue(t, emptyHostPanicMsg, func() {
		NewMultiURLForHost("grpc", "", "", 123)
	})
}

func TestNewMultiURLForAddresses(t *testing.T) {
	ip1234 := netip.MustParseAddr("1.2.3.4")
	assert.PanicsWithValue(t, emptySchemePanicMsg, func() {
		NewMultiURLForAddresses("", "", 123, []netip.Addr{ip1234})
	})
	assert.PanicsWithValue(t, emptyAddressesPanicMsg, func() {
		NewMultiURLForAddresses("grpc", "", 123, nil)
	})
	assert.PanicsWithValue(t, emptyAddressesPanicMsg, func() {
		NewMultiURLForAddresses("grpc", "", 123, []netip.Addr{})
	})
}

func TestParseMultiURL(t *testing.T) {
	ip1234 := netip.MustParseAddr("1.2.3.4")
	ipv6 := netip.MustParseAddr("123::123")
	tests := []struct {
		input       string
		expected    MultiURL
		expectedErr string
	}{
		{
			input:       "",
			expectedErr: "scheme not found in: ",
		},
		{
			input:       ":123",
			expectedErr: "scheme not found in: :123",
		},
		{
			input:       "grpc:",
			expectedErr: "port not found in: grpc:",
		},
		{
			input:       "grpc:|",
			expectedErr: `port in grpc:|: strconv.ParseUint: parsing "": invalid syntax`,
		},
		{
			input:       "grpc:|123",
			expectedErr: `no IPs and no host in: grpc:|123`,
		},
		{
			input:       "grpc:1.2.3.4|99999",
			expectedErr: `port in grpc:1.2.3.4|99999: strconv.ParseUint: parsing "99999": value out of range`,
		},
		{
			input:       "grpc:1.2.3.4/example.com/|1234",
			expectedErr: `either IP(s) or host can be present, not both: grpc:1.2.3.4/example.com/|1234`,
		},
		{
			input:       "grpc:1.2.3.4//|1234",
			expectedErr: `invalid host/tlsHost in grpc:1.2.3.4//|1234`,
		},
		{
			input:    "grpc:1.2.3.4|1234",
			expected: NewMultiURLForAddresses("grpc", "", 1234, []netip.Addr{ip1234}),
		},
		{
			input:    "grpc:1.2.3.4,123::123|1234",
			expected: NewMultiURLForAddresses("grpc", "", 1234, []netip.Addr{ip1234, ipv6}),
		},
		{
			input:    "grpc:/example.com/|1234",
			expected: NewMultiURLForHost("grpc", "example.com", "", 1234),
		},
		{
			input:    "grpc:/example.com/tlsexample.com|1234",
			expected: NewMultiURLForHost("grpc", "example.com", "tlsexample.com", 1234),
		},
	}
	for _, tc := range tests {
		t.Run(tc.input, func(t *testing.T) {
			ma, err := ParseMultiURL(tc.input)
			if tc.expectedErr == "" {
				require.NoError(t, err)
				assert.Equal(t, tc.expected, ma)
				assert.Equal(t, tc.input, ma.String())
			} else {
				assert.EqualError(t, err, tc.expectedErr)
			}
		})
	}
}
