package conf

import (
	"encoding/json"
	"errors"
	"leafstalk/log"
	"reflect"
	"sync"

	"leafstalk/otherutils/deepcopy"
)

// EventFunc 动态配置事件回调函数类型定义
type EventFunc func(key string, val interface{})

// event 动态事件结构体
type event struct {
	sync.Mutex
	config map[string]interface{} // 本地缓存配置。用于初始化和对比新配置中的差异项，当存在差异项时进行回调处理使用
	list   map[string][]EventFunc // 所有事件的列表
}

var dynamicEvent *event // 动态事件实例

// initDynamicEvent 初始化动态配置事件
func initDynamicEvent(cfgCenter *ConfigCenterAgent, group string) (err error) {
	dynamicEvent = &event{
		list: make(map[string][]EventFunc),
	}

	// 初始化时先获取一次动态配置，将其保存到本地
	content, err := cfgCenter.GetConfig("dynamicConfig", group)
	if err != nil {
		return
	}

	if err = json.Unmarshal([]byte(content), &dynamicEvent.config); err != nil {
		log.Warnf("initDynamicEvent error %v", content)
		return
	}

	if dynamicEvent.config == nil {
		err = errors.New("exception in obtaining dynamic config, config is nil")
		return
	}

	// 开始监听动态配置变化
	return cfgCenter.ListenChanges("dynamicConfig", group, func(namespace, group, dataId, newContent string) {
		var newConfig map[string]interface{}
		if err = json.Unmarshal([]byte(newContent), &newConfig); err != nil {
			// 解析配置出错，打印错误日志并返回
			log.Errorf("error parsing dynamic config for listen, err:%+v, newContent:%v", err, newContent)
			return
		}
		log.Infof("initDynamicEvent content %v", newContent)

		keys := CompareMaps(dynamicEvent.config, newConfig)
		if len(keys) == 0 {
			return
		}

		dynamicEvent.Lock()
		defer dynamicEvent.Unlock()

		dynamicEvent.config = newConfig
		for _, key := range keys {
			dynamicEvent.CallBack(key)
		}
	})
}

// CallBack 触发一个分组的事件回调
func (e *event) CallBack(key string) {
	val := e.config[key]

	if cbfs, ok := e.list[key]; ok {
		for _, f := range cbfs {
			val2, err := deepcopy.Copy(val)
			if err != nil {
				log.Errorf("CallBack deepcopy error %v", err)
			}
			f(key, val2)
		}
	}
}

// CompareMaps 检查old 和 new 中每个 key 的值是否相等，返回不相等的key列表
func CompareMaps(old, new map[string]interface{}) (diffKeys []string) {
	if new == nil {
		return
	}

	for key := range old {
		value2, ok := new[key]
		if ok && !reflect.DeepEqual(old[key], value2) {
			diffKeys = append(diffKeys, key)
		}
	}

	for key := range new {
		if _, ok := old[key]; !ok {
			diffKeys = append(diffKeys, key)
		}
	}
	return diffKeys
}

// RegisterAndCall 往一个分组中注册事件并触发一次事件回调
// 这里的 keyGroup 表示一个配置键，同一个键可以有多个回调方法注册。
// 当键发生变化时，会触发该键下所有注册的回调事件。
func RegisterAndCall(key string, callback EventFunc) {
	dynamicEvent.Lock()
	defer dynamicEvent.Unlock()

	val := dynamicEvent.config[key]
	val2, err := deepcopy.Copy(val)
	if err != nil {
		log.Fatalf("RegisterAndCall deepcopy error %v", err)
	}

	dynamicEvent.list[key] = append(dynamicEvent.list[key], callback)
	callback(key, val2)
}
