// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

package v1alpha1_test

import (
	"context"
	"net"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
	"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/bundle"
	"github.com/talos-systems/talos/pkg/machinery/constants"
)

type dynamicConfigProvider struct {
	externalIPs []net.IP
}

// Hostname implements DynamicConfigProvider.
func (cp *dynamicConfigProvider) Hostname(ctx context.Context) ([]byte, error) {
	return []byte("talos-default-master-1"), nil
}

// ExternalIPs implements DynamicConfigProvider.
func (cp *dynamicConfigProvider) ExternalIPs(ctx context.Context) ([]net.IP, error) {
	return cp.externalIPs, nil
}

// TestApplyDynamicConfig check ApplyDynamicConfig works and is idempotent.
func TestApplyDynamicConfig(t *testing.T) {
	b, err := bundle.NewConfigBundle(
		bundle.WithInputOptions(
			&bundle.InputOptions{
				ClusterName: "talos-default",
				Endpoint:    "10.5.0.1",
				KubeVersion: constants.DefaultKubernetesVersion,
			},
		),
	)
	require.NoError(t, err)

	config := b.ControlPlane()

	ctx := context.Background()

	provider := &dynamicConfigProvider{
		externalIPs: []net.IP{
			net.ParseIP("10.2.0.3"),
			net.ParseIP("10.10.1.2"),
		},
	}

	err = config.ApplyDynamicConfig(ctx, provider)
	require.NoError(t, err)

	c, ok := config.(*v1alpha1.Config)

	require.True(t, ok)

	require.Equal(t, "talos-default-master-1", c.Machine().Network().Hostname())
	require.Equal(t, []string{"10.2.0.3", "10.10.1.2"}, c.MachineConfig.CertSANs())

	provider.externalIPs = []net.IP{
		net.ParseIP("10.2.0.3"),
		net.ParseIP("10.10.1.2"),
	}

	provider = &dynamicConfigProvider{
		externalIPs: []net.IP{
			net.ParseIP("10.2.0.3"),
			net.ParseIP("10.10.1.2"),
			net.ParseIP("10.10.1.3"),
		},
	}

	err = config.ApplyDynamicConfig(ctx, provider)
	require.NoError(t, err)
	require.Equal(t, []string{"10.2.0.3", "10.10.1.2", "10.10.1.3"}, c.MachineConfig.CertSANs())
	require.Equal(t, []string{"10.2.0.3", "10.10.1.2", "10.10.1.3"}, c.ClusterConfig.CertSANs())

	c.MachineConfig.MachineNetwork.NetworkInterfaces = append(c.MachineConfig.MachineNetwork.NetworkInterfaces, &v1alpha1.Device{
		DeviceVIPConfig: &v1alpha1.DeviceVIPConfig{
			SharedIP: "192.168.88.77",
		},
	})

	err = config.ApplyDynamicConfig(ctx, provider)
	require.NoError(t, err)
	require.Equal(t, []string{"10.2.0.3", "10.10.1.2", "10.10.1.3", "192.168.88.77"}, c.MachineConfig.CertSANs())
}
