package config

import (
	_ "embed"
	"testing"

	"github.com/stretchr/testify/assert"
	"gopkg.in/yaml.v3"
)

var (
	//go:embed testdata/full-config.yaml
	fullConfigData []byte
)

func TestValidateConfig(t *testing.T) {
	type testCase struct {
		name        string
		setConfig   func(c *RMSConfiguration)
		expectError bool
	}
	cases := []testCase{
		{name: "empty Provider", setConfig: func(c *RMSConfiguration) { c.Provider = "" }, expectError: true},
		{name: "invalid Provider", setConfig: func(c *RMSConfiguration) { c.Provider = "invalid" }, expectError: true},
		{name: "empty TCMS.URL", setConfig: func(c *RMSConfiguration) { c.TCMS.URL = "" }, expectError: true},
		{name: "empty TCMS.PlanExecutionURLFormat", setConfig: func(c *RMSConfiguration) { c.TCMS.PlanExecutionURLFormat = "" }, expectError: true},
		{name: "invalid ReclaimConfiguration.Interval", setConfig: func(c *RMSConfiguration) { c.ReclaimConfiguration.Interval = "invalid" }, expectError: true},
		{name: "negative K8s.RequestBurst", setConfig: func(c *RMSConfiguration) { c.K8s.RequestBurst = -1 }, expectError: true},
		{name: "zero K8s.RequestBurst", setConfig: func(c *RMSConfiguration) { c.K8s.RequestBurst = 0 }, expectError: true},
		{name: "negative K8s.RequestQPS", setConfig: func(c *RMSConfiguration) { c.K8s.RequestQPS = -1 }, expectError: true},
		{name: "zero K8s.RequestQPS", setConfig: func(c *RMSConfiguration) { c.K8s.RequestQPS = 0 }, expectError: true},
		{name: "empty statisticsService.PrometheusURL", setConfig: func(c *RMSConfiguration) { c.StatisticsService.PrometheusURL = "" }, expectError: true},
		{name: "zero statisticsService.staticResourcePoolMetrics.cpuCores", setConfig: func(c *RMSConfiguration) { c.StatisticsService.StaticResourcePoolMetrics.CPUCores = 0 }, expectError: true},
		{name: "nagative statisticsService.staticResourcePoolMetrics.memoryBytes", setConfig: func(c *RMSConfiguration) { c.StatisticsService.StaticResourcePoolMetrics.MemoryBytes = -1 }, expectError: true},
		{name: "negative TestbedPerUser", setConfig: func(c *RMSConfiguration) { c.ResourceQuota.TestbedPerUser = -1 }, expectError: true},
		{name: "empty tc setup image image", setConfig: func(c *RMSConfiguration) { c.K8s.Images.TCSetup = "" }, expectError: true},
		{name: "empty sdk image", setConfig: func(c *RMSConfiguration) { c.K8s.Images.SDKServer = "" }, expectError: true},
		{name: "empty csr signer name", setConfig: func(c *RMSConfiguration) { c.K8s.CSRSignerName = "" }, expectError: true},
	}
	for _, testcase := range cases {
		t.Run(testcase.name, func(t *testing.T) {
			var rmsConfig RMSConfiguration
			assert.Nil(t, yaml.Unmarshal(fullConfigData, &rmsConfig))

			testcase.setConfig(&rmsConfig)

			if testcase.expectError {
				assert.Error(t, rmsConfig.Validate(), testcase.name)
			} else {
				assert.NoError(t, rmsConfig.Validate(), testcase.name)
			}
		})
	}
}

func TestParseConfig(t *testing.T) {
	var originalConfig, parsedConfig map[string]interface{}
	assert.Nil(t, yaml.Unmarshal(fullConfigData, &originalConfig))

	assert.Nil(t, ParseConfig(fullConfigData))
	cookedConfigData, err := yaml.Marshal(DefaultRMSConfiguration)
	assert.Nil(t, err)
	assert.Nil(t, yaml.Unmarshal(cookedConfigData, &parsedConfig))
	// unequal indicates some config might not be parsed properly
	assert.Equal(t, originalConfig, parsedConfig)
}
