package v1

import (
	"reflect"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
	// For test only
	ConditionTest ClusterConditionType = "Test"
)

func TestUpdateClusterCondition(t *testing.T) {
	time := metav1.Now()

	TestType := ClusterConditionType("TestType")

	clusterStatus := ClusterStatus{
		Conditions: []ClusterCondition{
			{
				Type:               TestType,
				Status:             ConditionTrue,
				Reason:             "successfully",
				Message:            "sync successfully",
				LastProbeTime:      time,
				LastTransitionTime: metav1.NewTime(time.Add(1000)),
			},
		},
	}
	tests := []struct {
		status     *ClusterStatus
		conditions ClusterCondition
		expected   bool
		desc       string
	}{
		{
			status: &clusterStatus,
			conditions: ClusterCondition{
				Type:               TestType,
				Status:             ConditionTrue,
				Reason:             "successfully",
				Message:            "sync successfully",
				LastProbeTime:      time,
				LastTransitionTime: metav1.NewTime(time.Add(1000))},
			expected: false,
			desc:     "all equal, no update",
		},
		{
			status: &clusterStatus,
			conditions: ClusterCondition{
				Type:               BandwidthThrottle,
				Status:             ConditionTrue,
				Reason:             "successfully",
				Message:            "reach total limit",
				LastProbeTime:      time,
				LastTransitionTime: metav1.NewTime(time.Add(1000))},
			expected: true,
			desc:     "not equal Type, should get updated",
		},
		{
			status: &clusterStatus,
			conditions: ClusterCondition{
				Type:               BandwidthThrottle,
				Status:             ConditionFalse,
				Reason:             "successfully",
				Message:            "reach total limit",
				LastProbeTime:      time,
				LastTransitionTime: metav1.NewTime(time.Add(1000))},
			expected: true,
			desc:     "not equal Status, should get updated",
		},
	}

	for _, test := range tests {
		resultStatus := UpdateClusterCondition(test.status, &test.conditions)

		assert.Equal(t, test.expected, resultStatus, test.desc)
	}
}
func TestFindStatusCondition(t *testing.T) {
	tests := []struct {
		name          string
		conditions    []ClusterCondition
		conditionType ClusterConditionType
		expected      *ClusterCondition
	}{
		{
			name: "not-present",
			conditions: []ClusterCondition{
				{Type: BandwidthThrottle},
			},
			conditionType: ClusterSuspended,
			expected:      nil,
		},
		{
			name: "present",
			conditions: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ClusterSuspended},
			},
			conditionType: ClusterSuspended,
			expected:      &ClusterCondition{Type: ClusterSuspended},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			actual := FindStatusCondition(test.conditions, test.conditionType)
			if !reflect.DeepEqual(actual, test.expected) {
				t.Error(actual)
			}
		})
	}
}

func TestSetStatusCondition(t *testing.T) {
	oneHourBefore := time.Now().Add(-1 * time.Hour)
	oneHourAfter := time.Now().Add(1 * time.Hour)

	tests := []struct {
		name       string
		conditions []ClusterCondition
		toAdd      ClusterCondition
		expected   []ClusterCondition
	}{
		{
			name: "should-add",
			conditions: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ConditionTest},
			},
			toAdd: ClusterCondition{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}, LastProbeTime: metav1.Time{Time: oneHourBefore}, Reason: "reason", Message: "message"},
			expected: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ConditionTest},
				{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}, LastProbeTime: metav1.Time{Time: oneHourBefore}, Reason: "reason", Message: "message"},
			},
		},
		{
			name: "use-supplied-time",
			conditions: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ClusterSuspended, Status: ConditionFalse},
				{Type: ConditionTest},
			},
			toAdd: ClusterCondition{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}, Reason: "reason", Message: "message"},
			expected: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}, Reason: "reason", Message: "message"},
				{Type: ConditionTest},
			},
		},
		{
			name: "update-fields",
			conditions: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}},
				{Type: ConditionTest},
			},
			toAdd: ClusterCondition{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourAfter}, Reason: "reason", Message: "message"},
			expected: []ClusterCondition{
				{Type: BandwidthThrottle},
				{Type: ClusterSuspended, Status: ConditionTrue, LastTransitionTime: metav1.Time{Time: oneHourBefore}, Reason: "reason", Message: "message"},
				{Type: ConditionTest},
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			SetStatusCondition(&test.conditions, test.toAdd)
			if !reflect.DeepEqual(test.conditions, test.expected) {
				t.Error(test.conditions)
			}
		})
	}
}
