package factory

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

const (
	testNs = "ns"
)

func TestGenRevision(t *testing.T) {
	re := require.New(t)

	cm1 := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "cm1",
			Namespace: testNs,
			Labels: map[string]string{
				"label1": "value1",
			},
		},
		Data: map[string]string{
			"key1": "value1",
			"key2": "value2",
		},
	}

	cm2 := &v1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Name:      "cm2",
			Namespace: testNs,
		},
		Data: map[string]string{
			"key3": "value3",
			"key4": "value4",
		},
	}
	clusterCli := fake.NewClientBuilder().WithObjects(cm1, cm2).Build()

	podSpec := &v1.PodSpec{
		Containers: []v1.Container{
			{
				Name: "container1",
				Env: []v1.EnvVar{
					{
						Name:  "env1",
						Value: "value1",
					},
				},
				VolumeMounts: []v1.VolumeMount{
					{
						Name:      "vol1",
						MountPath: "/path1",
					},
				},
			},
		},
		Volumes: []v1.Volume{
			{
				Name: "vol1",
				VolumeSource: v1.VolumeSource{
					ConfigMap: &v1.ConfigMapVolumeSource{
						LocalObjectReference: v1.LocalObjectReference{
							Name: "cm1",
						},
					},
				},
			},
		},
	}

	revisionOriginal, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)

	// Recalculate the revision, this should be the same.
	revisionRecalculated, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)
	re.Equal(revisionOriginal, revisionRecalculated)

	// Change the data of cm1, this should generate a different revision.
	cm1.Data["key1"] = "value1-changed"
	re.NoError(clusterCli.Update(context.Background(), cm1))
	revisionChanged, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)
	re.NotEqual(revisionOriginal, revisionChanged)

	// Change the data back, this should generate the original revision.
	cm1.Data["key1"] = "value1"
	re.NoError(clusterCli.Update(context.Background(), cm1))
	revisionChangedBack, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)
	re.Equal(revisionOriginal, revisionChangedBack)

	// Change the metadata should NOT affect the revision.
	cm1.Labels["label1"] = "value1-changed"
	re.NoError(clusterCli.Update(context.Background(), cm1))
	revisionChangedLabel, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)
	re.Equal(revisionOriginal, revisionChangedLabel)

	// Change the pod spec should generate a different revision.
	podSpec.Containers[0].Env[0].Value = "value1-changed"
	revisionPodChanged, err := GenRevision(context.Background(), testNs, clusterCli, podSpec, "cm1", "cm2")
	re.NoError(err)
	re.NotEqual(revisionOriginal, revisionPodChanged)
}
