package config

import (
	"fmt"
	"log"
	"path"
	"path/filepath"
	"sync"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/viper"
)

type ConfigInterface interface {
	Load()
	RegisterOnChangeCallback(f func())
	Get(key string) interface{}
}
type Config struct {
	cbLock    sync.Mutex
	Callbacks []func()
	Env       string
}

func NewConfig() ConfigInterface {
	return &Config{}
}
func (c *Config) Load() {
	pathConfig := "./../../config.json"
	realPath, err := filepath.Abs(pathConfig)
	if err != nil {
		log.Fatal(err.Error())
	}
	viper.SetConfigName("config")
	viper.SetConfigType("json")
	viper.AddConfigPath(path.Dir(realPath))
	if err := viper.ReadInConfig(); err != nil {
		log.Fatalf("Failed To Read Configuration File: %v", err)
	}
	c.SetEnv()
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		c.SetEnv()
		log.Printf("Configuration File Changed : %s", e.Name)
		c.cbLock.Lock()
		for _, callback := range c.Callbacks {
			if callback != nil {
				callback()
			}
		}
		c.cbLock.Unlock()
	})
}
func (c *Config) RegisterOnChangeCallback(f func()) {
	c.cbLock.Lock()
	defer c.cbLock.Unlock()
	c.Callbacks = append(c.Callbacks, f)
}
func (c *Config) SetEnv() {
	envString := viper.GetString("env")
	log.Println(envString)
	c.Env = envString
}
func (c *Config) Get(key string) interface{} {
	envString := fmt.Sprintf("%v.%v", "config", c.Env)
	return viper.Get(fmt.Sprintf("%v.%v", envString, key))
}
