package config

import (
	"github.com/UpmeshLTD/urus-aio/infrastructure/config/registry"
	"strings"
	"sync"

	"github.com/spf13/viper"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

var (
	once sync.Once
)

var _ = Describe("Provider", func() {
	var (
		provider Provider
	)

	BeforeEach(func() {
		once.Do(func() {
			registry.RegisterConfig("test_config", registry.NewConfig(func(v *viper.Viper) interface{} {
				return v.GetStringMap("test_config")
			}))

			registry.RegisterConfig("test_default_config", registry.NewConfig(func(v *viper.Viper) interface{} {
				return v.GetStringMap("test_default_config")
			}, registry.WithSetDefault(func(v *viper.Viper) {
				v.SetDefault("test_default_config", map[string]interface{}{
					"default_int_value": 100,
				})
			})))
		})
	})

	Describe("with default Viper initializer", func() {
		BeforeEach(func() {
			provider = NewProvider()
		})

		Describe("Get", func() {
			FIt("should return default config value", func() {
				c := provider.Get("test_default_config")
				Expect(c).Should(HaveKey("default_int_value"))
				Expect(c).Should(ContainElement(100))
			})

			It("should return config value", func() {
				c := provider.Get("test_config")
				Expect(c).Should(HaveKey("int_value"))
				Expect(c).Should(ContainElement(999))
			})
		})
	})

	When("with customized Viper provider", func() {
		BeforeEach(func() {
			provider = NewProvider(WithViperInitializer(func(v *viper.Viper) {
				v.SetConfigName("another-app-config")
				v.SetConfigType("yaml")
				v.AddConfigPath("$APP_CONFIG_DIR")
				v.AddConfigPath(".")
				v.AddConfigPath("$HOME")
				v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
				v.SetEnvPrefix("APP")
				v.AutomaticEnv()
			}))
		})

		Describe("Get", func() {
			It("should return default config value", func() {
				c := provider.Get("test_default_config")
				Expect(c).Should(HaveKey("default_int_value"))
				Expect(c).Should(ContainElement(100))
			})

			It("should return config value", func() {
				c := provider.Get("test_config")
				Expect(c).Should(HaveKey("int_value"))
				Expect(c).Should(ContainElement(111))
			})
		})
	})
})
