package main

import (
	"context"
	"isle/bootstrap"
	"isle/nebula"
	"isle/toolkit"
	"net/netip"
	"testing"

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

func TestHostList(t *testing.T) {
	t.Parallel()

	var ipNet nebula.IPNet
	require.NoError(t, ipNet.UnmarshalText([]byte("172.16.0.0/16")))

	caCreds, err := nebula.NewCACredentials("test.com", ipNet)
	require.NoError(t, err)

	type host struct {
		name             string
		ip               string
		publicAddr       string
		storageInstances []bootstrap.GarageHostInstance
	}

	tests := []struct {
		name  string
		hosts []host
		want  any
	}{
		{
			name: "no hosts",
			want: []any{},
		},
		{
			name: "single",
			hosts: []host{
				{
					name: "a",
					ip:   "172.16.0.1",
				},
			},
			want: []map[string]any{
				{
					"name": "a",
					"vpn": map[string]any{
						"ip": "172.16.0.1",
					},
				},
			},
		},
		{
			name: "multiple",
			hosts: []host{
				{
					name: "a",
					ip:   "172.16.0.1",
				},
				{
					name:       "b",
					ip:         "172.16.0.2",
					publicAddr: "1.1.1.1:80",
					storageInstances: []bootstrap.GarageHostInstance{{
						ID:        "storageInstanceID",
						RPCPort:   9000,
						S3APIPort: 9001,
					}},
				},
			},
			want: []map[string]any{
				{
					"name": "a",
					"vpn": map[string]any{
						"ip": "172.16.0.1",
					},
				},
				{
					"name": "b",
					"vpn": map[string]any{
						"ip":          "172.16.0.2",
						"public_addr": "1.1.1.1:80",
					},
					"storage": map[string]any{
						"allocations": []any{
							map[string]any{
								"id":          "storageInstanceID",
								"rpc_port":    9000,
								"s3_api_port": 9001,
							},
						},
					},
				},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			var (
				h     = newRunHarness(t)
				hosts = map[nebula.HostName]bootstrap.Host{}
			)

			for _, testHost := range test.hosts {
				var (
					hostName nebula.HostName
					ip       = netip.MustParseAddr(testHost.ip)
				)
				require.NoError(
					t, hostName.UnmarshalText([]byte(testHost.name)),
				)

				host, _, err := bootstrap.NewHost(caCreds, hostName, ip)
				require.NoError(t, err)

				host.Nebula.PublicAddr = testHost.publicAddr
				host.Garage.Instances = testHost.storageInstances

				hosts[hostName] = host
			}

			h.daemonRPC.
				On("GetBootstrap", toolkit.MockArg[context.Context]()).
				Return(bootstrap.Bootstrap{Hosts: hosts}, nil).
				Once()

			h.runAssertStdout(t, test.want, "host", "list")
		})
	}
}