package models

import (
	"testing"

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

func TestSKUDifference_CalculateTolerance(t *testing.T) {
	t.Run("zero0", func(t *testing.T) {
		s := &SKUComparison{
			SKU:               "a",
			CountInCoreSvc:    0,
			CountInMetering:   0,
			CountInMeteringV2: 0,
		}

		s.CalculateTolerance(0.1)
		s.CalculateToleranceV2()
		assert.Equal(t, float64(0), s.DifferenceRatio)
		assert.Equal(t, true, s.WithinTolerableRange)
		assert.Equal(t, float64(0), s.DifferenceRatioV2)
		assert.Equal(t, true, s.WithinTolerableRangeV2)
	})
	t.Run("zero1", func(t *testing.T) {
		s := SKUComparison{
			SKU:               "a",
			CountInCoreSvc:    0,
			CountInMetering:   1,
			CountInMeteringV2: 0,
		}

		s.CalculateTolerance(0.1)
		s.CalculateToleranceV2()
		assert.Equal(t, float64(1), s.DifferenceRatio)
		assert.Equal(t, false, s.WithinTolerableRange)
		assert.Equal(t, float64(-1), s.DifferenceRatioV2)
		assert.Equal(t, false, s.WithinTolerableRangeV2)
	})
	t.Run("zero2", func(t *testing.T) {
		s := SKUComparison{
			SKU:               "a",
			CountInCoreSvc:    1,
			CountInMetering:   0,
			CountInMeteringV2: 1,
		}

		s.CalculateTolerance(0.1)
		s.CalculateToleranceV2()
		assert.Equal(t, float64(-1), s.DifferenceRatio)
		assert.Equal(t, false, s.WithinTolerableRange)
		assert.Equal(t, float64(1), s.DifferenceRatioV2)
		assert.Equal(t, false, s.WithinTolerableRangeV2)
	})

}

func TestComparatorBuilder(t *testing.T) {
	cluster1 := ClusterInfo{
		TenantID:  "tenant1",
		ProjectID: "project1",
		ClusterID: "cluster1",
	}
	cluster2 := ClusterInfo{
		TenantID:  "tenant2",
		ProjectID: "project2",
		ClusterID: "cluster2",
	}
	cluster3 := ClusterInfo{
		TenantID:  "tenant3",
		ProjectID: "project3",
		ClusterID: "cluster3",
	}
	cluster4 := ClusterInfo{
		TenantID:  "tenant4",
		ProjectID: "project4",
		ClusterID: "cluster4",
	}
	comparator := ComparatorBuilder(11111, 222222).
		InMetering(cluster1, "node:xxxx:size1", 3).
		InMetering(cluster1, "iops:xxxx:size1", 4*3000).
		InMetering(cluster1, "disk:xxxx:size1", 3*200).
		InMeteringV2(cluster1, "node:xxxx:size1", 3).
		InMeteringV2(cluster1, "iops:xxxx:size1", 4*3000).
		InMeteringV2(cluster1, "disk:xxxx:size1", 3*200).
		InCoreSvc(cluster1, "node:xxxx:size1", 1).
		InCoreSvc(cluster1, "iops:xxxx:size1", 2*3000).
		InCoreSvc(cluster1, "disk:xxxx:size1", 3*100).
		InCoreSvc(cluster1, "node:xxxx:size1", 2).
		InCoreSvc(cluster1, "iops:xxxx:size1", 2*3000).
		InCoreSvc(cluster1, "disk:xxxx:size1", 3*100).
		InMetering(cluster2, "node:xxxx:sizecommon", 3).
		InMetering(cluster2, "iops:xxxx:sizecommon", 3*3000).
		InMeteringV2(cluster2, "node:xxxx:sizecommon", 3).
		InMeteringV2(cluster2, "iops:xxxx:sizecommon", 3*3000).
		InCoreSvc(cluster3, "node:xxxx:sizecommon", 7).
		InCoreSvc(cluster3, "iops:xxxx:sizecommon", 7*3000).
		InMetering(cluster4, "node:xxxx:size4", 10).
		InMetering(cluster4, "iops:xxxx:size4", 3*3000).
		InMeteringV2(cluster4, "node:xxxx:size4", 10).
		InMeteringV2(cluster4, "iops:xxxx:size4", 3*3000).
		InCoreSvc(cluster4, "node:xxxx:size4", 3).
		InCoreSvc(cluster4, "iops:xxxx:size4", 3*3000).
		InCoreSvc(cluster4, "node:xxxx:size4", 1).
		InCoreSvc(cluster4, "iops:xxxx:size4", 3*10)

	comparator.CalculateResult(0.01)
	comparator.ToString()

	assert.Equal(t, true, comparator.Clusters["cluster1"].WithinTolerableRange)
	assert.Equal(t, true, comparator.Clusters["cluster1"].InMetering)
	assert.Equal(t, true, comparator.Clusters["cluster1"].InCoreSvc)
	assert.Equal(t, true, comparator.Clusters["cluster1"].InMeteringV2)

	assert.Equal(t, false, comparator.Clusters["cluster2"].WithinTolerableRange)
	assert.Equal(t, false, comparator.Clusters["cluster2"].InCoreSvc)

	assert.Equal(t, false, comparator.Clusters["cluster3"].WithinTolerableRange)
	assert.Equal(t, false, comparator.Clusters["cluster3"].InMetering)

	assert.Equal(t, false, comparator.Clusters["cluster4"].WithinTolerableRange)
	assert.Equal(t, true, comparator.Clusters["cluster4"].InMetering)
	assert.Equal(t, true, comparator.Clusters["cluster4"].InCoreSvc)
	assert.Equal(t, true, comparator.Clusters["cluster4"].InMeteringV2)
	assert.Equal(t, false, comparator.Clusters["cluster4"].SKUs["node:xxxx:size4"].WithinTolerableRange)
	assert.Equal(t, true, comparator.Clusters["cluster4"].SKUs["iops:xxxx:size4"].WithinTolerableRange)
	assert.Equal(t, true, comparator.Clusters["cluster4"].SKUs["node:xxxx:size4"].WithinTolerableRangeV2)
	assert.Equal(t, true, comparator.Clusters["cluster4"].SKUs["iops:xxxx:size4"].WithinTolerableRangeV2)

	comparator.CalculateResult(0.001)
	assert.Equal(t, false, comparator.Clusters["cluster4"].SKUs["node:xxxx:size4"].WithinTolerableRange)
	assert.Equal(t, false, comparator.Clusters["cluster4"].SKUs["iops:xxxx:size4"].WithinTolerableRange)
	assert.Equal(t, true, comparator.Clusters["cluster4"].SKUs["node:xxxx:size4"].WithinTolerableRangeV2)
	assert.Equal(t, true, comparator.Clusters["cluster4"].SKUs["iops:xxxx:size4"].WithinTolerableRangeV2)
	comparator.ToString()

	unmatchedIDs, unmatchedDetails := comparator.UnmatchedClusters()
	assert.Contains(t, unmatchedIDs, "cluster2")
	assert.Contains(t, unmatchedIDs, "cluster3")
	assert.Contains(t, unmatchedIDs, "cluster4")
	assert.NotContains(t, unmatchedIDs, "cluster1")
	assert.Len(t, unmatchedDetails, 3)

	unmatchedV2IDs, unmatchedV2Details := comparator.UnmatchedClustersV2()
	assert.NotContains(t, unmatchedV2IDs, "cluster1")
	assert.Len(t, unmatchedV2Details, len(unmatchedV2IDs))
}
