package network_test

import (
	_ "embed"
	"net"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/mock/gomock"

	"github.com/hetznercloud/cli/internal/cmd/network"
	"github.com/hetznercloud/cli/internal/testutil"
	"github.com/hetznercloud/hcloud-go/v2/hcloud"
)

//go:embed testdata/create_response.json
var createResponseJSON string

func TestCreate(t *testing.T) {
	fx := testutil.NewFixture(t)
	defer fx.Finish()

	cmd := network.CreateCmd.CobraCommand(fx.State())
	fx.ExpectEnsureToken()

	_, ipRange, _ := net.ParseCIDR("10.0.0.0/24")
	n := &hcloud.Network{
		ID:      123,
		Name:    "myNetwork",
		IPRange: ipRange,
	}

	fx.Client.NetworkClient.EXPECT().
		Create(gomock.Any(), hcloud.NetworkCreateOpts{
			Name:    "myNetwork",
			IPRange: ipRange,
			Labels:  make(map[string]string),
		}).
		Return(n, nil, nil)
	fx.Client.NetworkClient.EXPECT().
		GetByID(gomock.Any(), int64(123)).
		Return(n, nil, nil)

	out, errOut, err := fx.Run(cmd, []string{"--name", "myNetwork", "--ip-range", "10.0.0.0/24"})

	expOut := "Network 123 created\n"

	require.NoError(t, err)
	assert.Empty(t, errOut)
	assert.Equal(t, expOut, out)
}

func TestCreateJSON(t *testing.T) {
	fx := testutil.NewFixture(t)
	defer fx.Finish()

	time.Local = time.UTC

	cmd := network.CreateCmd.CobraCommand(fx.State())
	fx.ExpectEnsureToken()

	_, ipRange, _ := net.ParseCIDR("10.0.0.0/24")
	n := &hcloud.Network{
		ID:            123,
		Name:          "myNetwork",
		IPRange:       ipRange,
		Created:       time.Date(2016, 1, 30, 23, 50, 0, 0, time.UTC),
		Labels:        make(map[string]string),
		Servers:       []*hcloud.Server{{ID: 1}, {ID: 2}, {ID: 3}},
		LoadBalancers: []*hcloud.LoadBalancer{{ID: 4}, {ID: 5}, {ID: 6}},
		Routes:        []hcloud.NetworkRoute{},
		Subnets:       []hcloud.NetworkSubnet{},
	}

	fx.Client.NetworkClient.EXPECT().
		Create(gomock.Any(), hcloud.NetworkCreateOpts{
			Name:    "myNetwork",
			IPRange: ipRange,
			Labels:  make(map[string]string),
		}).
		Return(n, nil, nil)
	fx.Client.NetworkClient.EXPECT().
		GetByID(gomock.Any(), n.ID).
		Return(n, nil, nil)

	jsonOut, out, err := fx.Run(cmd, []string{"-o=json", "--name", "myNetwork", "--ip-range", "10.0.0.0/24"})

	expOut := "Network 123 created\n"

	require.NoError(t, err)
	assert.Equal(t, expOut, out)
	assert.JSONEq(t, createResponseJSON, jsonOut)
}

func TestCreateProtection(t *testing.T) {
	fx := testutil.NewFixture(t)
	defer fx.Finish()

	cmd := network.CreateCmd.CobraCommand(fx.State())
	fx.ExpectEnsureToken()

	_, ipRange, _ := net.ParseCIDR("10.0.0.0/24")
	n := &hcloud.Network{
		ID:      123,
		Name:    "myNetwork",
		IPRange: ipRange,
	}

	fx.Client.NetworkClient.EXPECT().
		Create(gomock.Any(), hcloud.NetworkCreateOpts{
			Name:    "myNetwork",
			IPRange: ipRange,
			Labels:  make(map[string]string),
		}).
		Return(n, nil, nil)
	fx.Client.NetworkClient.EXPECT().
		ChangeProtection(gomock.Any(), n, hcloud.NetworkChangeProtectionOpts{
			Delete: hcloud.Ptr(true),
		}).
		Return(&hcloud.Action{ID: 123}, nil, nil)
	fx.ActionWaiter.EXPECT().WaitForActions(gomock.Any(), gomock.Any(), &hcloud.Action{ID: 123}).Return(nil)
	fx.Client.NetworkClient.EXPECT().
		GetByID(gomock.Any(), n.ID).
		Return(n, nil, nil)

	out, errOut, err := fx.Run(cmd, []string{"--name", "myNetwork", "--ip-range", "10.0.0.0/24", "--enable-protection", "delete"})

	expOut := `Network 123 created
Resource protection enabled for Network 123
`

	require.NoError(t, err)
	assert.Empty(t, errOut)
	assert.Equal(t, expOut, out)
}
