package globals

import (
	"container/list"
	"encoding/json"
	"netease_control_center/interfaces/log"
	"netease_control_center/modules/storage"
	"strconv"
	"sync"
	"time"
)

type CfgListType []map[string]interface{}

type CfgKey string

type CbList struct {
	// element is: func()
	List *list.List
	lock sync.RWMutex
}
type CfgVal struct {
	Val      interface{} `json:"val"`
	DefVal   interface{} `json:"-"`
	cbLists  *CbList     `json:"-"`
	NeedSave bool        `json:"needSave"`
}

var (
	cfgList2Lock sync.Mutex
)

type CallCbType uint8

const (
	REBOOT_CALL CallCbType = iota + 0
	CHANGE_CALL
	FORCE_CALL
)

const (
	cfgListTimeKey CfgKey = "cfgListTime"
	cfgListVuiKey  CfgKey = "cfgListVui"
	cfgListStrKey  CfgKey = "cfgListStr"
	// time : time.Duration
	VoiceInputSilentTime       CfgKey = "voiceInputSilentTime"
	VoiceInputMaxTime          CfgKey = "voiceInputMaxTime"
	VoiceRecogMaxTime          CfgKey = "voiceRecogMaxTime"
	VoiceExecResultMaxTimeout  CfgKey = "voiceExecResultMaxTimeout"
	T1Timeout                  CfgKey = "t1Timeout"
	T2Timeout                  CfgKey = "t2Timeout"
	WifiAutoConnectTimeout     CfgKey = "wifiAutoConnectTimeout"
	AutoExitWifiParingTimeout  CfgKey = "autoExitWifiParingTimeout"
	WifiParingConnectTimeout   CfgKey = "wifiParingConnectTimeout"
	BootUpVuiDelayTime         CfgKey = "bootUpVuiDelayTime"
	WifiParingFirstVuiKeepTime CfgKey = "wifiParingFirstVuiKeepTime"
	IconKeepTime               CfgKey = "iconKeepTime"
	IconT1T3                   CfgKey = "iconT1T3"
	RepeatCmdDurtion           CfgKey = "repeatCmdDurtion"
	LowLevelTaskWaitTime       CfgKey = "lowLevelTaskWaitTime"
	DlnaWaitNextTime           CfgKey = "dlnaWaitNextTime"
	AirPlayPrivilege           CfgKey = "airPlayPrivilege"

	// vui : int
	DefaultVol           CfgKey = "defaultVol"
	IncVolLevel          CfgKey = "incVolLevel"
	IconLedSwitch        CfgKey = "iconLedSwitch"
	IconLedMusicPlayMode CfgKey = "iconLedMusicPlayMode"
	DirectLedBrightness  CfgKey = "directLedBrightness"
	VolMixBegin          CfgKey = "volMixBegin"
	VolLowThreshold      CfgKey = "volLowThreshold"
	VolLowVal            CfgKey = "volLowVal"
	VolMiddleThreshold   CfgKey = "volMiddleThreshold"
	VolMiddleVal         CfgKey = "volMiddleVal"
	VolHighThreshold     CfgKey = "volHighThreshold"
	VolHighVal           CfgKey = "volHighVal"
	VolMixRestoreTime    CfgKey = "volMixRestoreTime"
	// local : int
	CloseBlueWhenReboot CfgKey = "closeBlueWhenReboot"

	// str : string
	TtsType   CfgKey = "ttsType"
	MicCron   CfgKey = "micCron"
	WakeupArg CfgKey = "wakeupArg"
)

func volCb1(e interface{}, cbType CallCbType) {
	log.Println(log.ErrorLog, "volchange 1")
}
func volCb2(e interface{}, cbType CallCbType) {
	log.Println(log.ErrorLog, "volchange 2")
}
func init() {
	DefaultVol.RegisterCb(volCb1)
	DefaultVol.RegisterCb(volCb2)

	TtsType.RegisterCb(TtsSelCb)
}

func (this CfgKey) GetKey() CfgKey {
	return this
}

func (this CfgKey) GetCfgListTime() time.Duration {
	if val, ok := cfgListMap[this]; ok {
		if valTime, ok := val.Val.(time.Duration); ok {
			return valTime
		}
	}
	return 0
}

func (this CfgKey) GetCfgListVui() int {
	if val, ok := cfgListMap[this]; ok {
		if valInt, ok := val.Val.(int); ok {
			return valInt
		}
	}
	return 0
}

func (this CfgKey) GetCfgListStr() string {
	if val, ok := cfgListMap[this]; ok {
		if valStr, ok := val.Val.(string); ok {
			return valStr
		}
	}
	return ""
}

func (this CfgKey) RegisterCb(cb func(e interface{}, cbType CallCbType)) {
	cbListTmp := cfgListMap[this].cbLists
	cbListTmp.Push(cb)
	cfgVal := CfgVal{Val: cfgListMap[this].Val, DefVal: cfgListMap[this].DefVal,
		cbLists: cbListTmp, NeedSave: cfgListMap[this].NeedSave}
	cfgListMap[this] = cfgVal
}

func (this CfgKey) ForceCallCb() {
	cfgListMap[this].cbLists.Exec(cfgListMap[this].Val, FORCE_CALL)
}

func (this CfgKey) CfgKeyValRestore() {
	cfgVal := CfgVal{Val: cfgListMap[this].DefVal, DefVal: cfgListMap[this].DefVal,
		cbLists: cfgListMap[this].cbLists, NeedSave: cfgListMap[this].NeedSave}
	cfgListMap[this] = cfgVal
}

var (
	uintTime map[string]time.Duration = map[string]time.Duration{
		"hour":        time.Hour,
		"minute":      time.Minute,
		"second":      time.Second,
		"millisecond": time.Millisecond,
		"microsecond": time.Microsecond,
		"nanosecond":  time.Nanosecond,
	}

	cfgListMap map[CfgKey]CfgVal = map[CfgKey]CfgVal{
		// time
		VoiceInputSilentTime: CfgVal{Val: 5 * time.Second, DefVal: 5 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VoiceInputMaxTime:    CfgVal{Val: 60 * time.Second, DefVal: 60 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VoiceRecogMaxTime:    CfgVal{Val: 3 * time.Second, DefVal: 3 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},

		VoiceExecResultMaxTimeout:  CfgVal{Val: 5 * time.Second, DefVal: 5 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		T1Timeout:                  CfgVal{Val: 60 * time.Second, DefVal: 60 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		T2Timeout:                  CfgVal{Val: 30 * time.Minute, DefVal: 30 * time.Minute, cbLists: &CbList{List: list.New()}, NeedSave: true},
		WifiAutoConnectTimeout:     CfgVal{Val: 120 * time.Second, DefVal: 120 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		AutoExitWifiParingTimeout:  CfgVal{Val: 30 * time.Minute, DefVal: 30 * time.Minute, cbLists: &CbList{List: list.New()}, NeedSave: true},
		WifiParingConnectTimeout:   CfgVal{Val: 30 * time.Second, DefVal: 30 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		BootUpVuiDelayTime:         CfgVal{Val: 0 * time.Second, DefVal: 0 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		WifiParingFirstVuiKeepTime: CfgVal{Val: 20 * time.Second, DefVal: 20 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		IconKeepTime:               CfgVal{Val: 3 * time.Second, DefVal: 3 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		IconT1T3:                   CfgVal{Val: 300 * time.Millisecond, DefVal: 300 * time.Millisecond, cbLists: &CbList{List: list.New()}, NeedSave: true},
		RepeatCmdDurtion:           CfgVal{Val: 30 * time.Second, DefVal: 30 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},
		LowLevelTaskWaitTime:       CfgVal{Val: 1 * time.Minute, DefVal: 1 * time.Minute, cbLists: &CbList{List: list.New()}, NeedSave: true},
		DlnaWaitNextTime:           CfgVal{Val: 2 * time.Second, DefVal: 2 * time.Second, cbLists: &CbList{List: list.New()}, NeedSave: true},

		// vui
		DefaultVol:           CfgVal{Val: 8, DefVal: 8, cbLists: &CbList{List: list.New()}, NeedSave: true},
		IncVolLevel:          CfgVal{Val: 2, DefVal: 2, cbLists: &CbList{List: list.New()}, NeedSave: true},
		DirectLedBrightness:  CfgVal{Val: 100, DefVal: 100, cbLists: &CbList{List: list.New()}, NeedSave: true},
		IconLedMusicPlayMode: CfgVal{Val: 3, DefVal: 3, cbLists: &CbList{List: list.New()}, NeedSave: true},
		IconLedSwitch:        CfgVal{Val: 1, DefVal: 1, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolMixBegin:          CfgVal{Val: 50, DefVal: 50, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolMixRestoreTime:    CfgVal{Val: 1000, DefVal: 1000, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolLowThreshold:      CfgVal{Val: 30, DefVal: 30, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolLowVal:            CfgVal{Val: 50, DefVal: 50, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolMiddleThreshold:   CfgVal{Val: 70, DefVal: 70, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolMiddleVal:         CfgVal{Val: 90, DefVal: 90, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolHighThreshold:     CfgVal{Val: 100, DefVal: 100, cbLists: &CbList{List: list.New()}, NeedSave: true},
		VolHighVal:           CfgVal{Val: 50, DefVal: 50, cbLists: &CbList{List: list.New()}, NeedSave: true},
		// local
		CloseBlueWhenReboot: CfgVal{Val: 1, DefVal: 1, cbLists: &CbList{List: list.New()}, NeedSave: true},

		// str
		TtsType:   CfgVal{Val: "orion", DefVal: "orion", cbLists: &CbList{List: list.New()}, NeedSave: true},
		MicCron:   CfgVal{Val: `{"startT":1514736000000,"endT":1514761200000,"mainSwitch":false,"lightSwitch":true}`, DefVal: `{"startT":1514736000000,"endT":1514761200000,"mainSwitch":false,"lightSwitch":true}`, cbLists: &CbList{List: list.New()}, NeedSave: false},
		WakeupArg: CfgVal{Val: `{"words":[]}`, DefVal: `{"words":[]}`, cbLists: &CbList{List: list.New()}, NeedSave: true},

		// switch
		AirPlayPrivilege: CfgVal{Val: 1, DefVal: 1, cbLists: &CbList{List: list.New()}, NeedSave: true},
	}
)

func GetGlobalCfgList() map[CfgKey]CfgVal {
	return cfgListMap
}

func SaveCfgList(cfgList CfgListType) error {
	data, err := json.Marshal(cfgList)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}
	return storage.Config_set(MODULE_CONTROLLER, SQL_KEY_CFG_LIST, string(data))
}

func SaveCfgList2Sql() {
	cfgList2Lock.Lock()
	defer cfgList2Lock.Unlock()

	SaveCfgListMap(cfgListMap)
}

func SaveCfgListMap(listMap map[CfgKey]CfgVal) error {
	data, err := json.Marshal(listMap)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}
	return storage.Config_set(MODULE_CONTROLLER, SQL_KEY_CFG_LIST, string(data))
}

func ReadCfgListMap() error {
	log.Printf(log.WarningLog, "before read:%+v\n", cfgListMap)

	var str string
	err := storage.Config_get(MODULE_CONTROLLER, SQL_KEY_CFG_LIST, &str)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}

	var listMap map[CfgKey]CfgVal
	err = json.Unmarshal([]byte(str), &listMap)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}

	var valEqual bool = false
	for k, _ := range listMap {
		switch cfgListMap[k].Val.(type) {
		case time.Duration:
			valEqual = (listMap[k].Val.(float64) != float64(cfgListMap[k].Val.(time.Duration)))
		case int:
			valEqual = (listMap[k].Val.(float64) != float64(cfgListMap[k].Val.(int)))
		default:
			valEqual = (listMap[k].Val != cfgListMap[k].Val)
		}
		if cfgListMap[k].NeedSave && valEqual {
			log.Printf(log.WarningLog, "key:%v, valOld:%+v, valNew:%+v\n", k, cfgListMap[k].Val, listMap[k].Val)
			tmp := cfgListMap[k]
			var valNew interface{}
			if _, ok := listMap[k].Val.(float64); ok {
				switch tmp.Val.(type) {
				case time.Duration:
					valNew = time.Duration(listMap[k].Val.(float64))
				case int:
					valNew = int(listMap[k].Val.(float64))
				}
			} else {
				valNew = listMap[k].Val
			}

			tmp.Val = valNew
			cfgListMap[k] = tmp
		}
	}

	log.Printf(log.WarningLog, "after read:%+v\n", cfgListMap)
	return nil
}

func SaveReadListMapTest() {
	tmp := cfgListMap[IconLedMusicPlayMode]
	tmp.Val = 2
	cfgListMap[IconLedMusicPlayMode] = tmp

	tmp = cfgListMap[DefaultVol]
	tmp.Val = 15
	cfgListMap[DefaultVol] = tmp

	log.Printf(log.WarningLog, "reverse:%+v\n", cfgListMap)

	SaveCfgListMap(cfgListMap)

	tmp = cfgListMap[IconLedMusicPlayMode]
	tmp.Val = 1
	cfgListMap[IconLedMusicPlayMode] = tmp

	tmp = cfgListMap[DefaultVol]
	tmp.Val = 12
	cfgListMap[DefaultVol] = tmp

	ReadCfgListMap()
}

func ReadCfgList(cfgList *CfgListType) error {
	var str string
	err := storage.Config_get(MODULE_CONTROLLER, SQL_KEY_CFG_LIST, &str)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}
	err = json.Unmarshal([]byte(str), cfgList)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return err
	}
	return nil
}

func ForceExecCfgListCb() {
	for k, _ := range cfgListMap {
		cfgListMap[k].cbLists.Exec(cfgListMap[k].Val, REBOOT_CALL)
	}
}

/**
  服务端需要保证值的正确性
*/
func SetAndSaveCfgList(cfgList CfgListType) {
	SetCfgList(cfgList)

	//SaveCfgList(cfgList)
	SaveCfgListMap(cfgListMap)
}

func GetCfgList(cfgList string) string {
	var tmp CfgListType
	err := json.Unmarshal([]byte(cfgList), &tmp)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return ""
	}
	log.Println(log.WarningLog, "in paras: ", cfgList)

	for i := 0; i < len(tmp); i++ {
		if cfgKey, ok := tmp[i]["key"]; ok {
			if cfgKeyStr, ok := cfgKey.(string); ok {
				if cfgListTimeKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := tmp[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										timeDurationNs := cfgListMap[CfgKey(key)].Val.(time.Duration).Nanoseconds()
										v["value"] = strconv.FormatInt(timeDurationNs, 10)
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}

							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else if cfgListVuiKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := tmp[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										v["value"] = strconv.Itoa(cfgListMap[CfgKey(key)].Val.(int))
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}
							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else if cfgListStrKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := tmp[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										v["value"] = cfgListMap[CfgKey(key)].Val.(string)
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}
							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else {
					log.Println(log.ErrorLog, "invalid key:", cfgKeyStr)
				}
			}
		} else {
			log.Println(log.ErrorLog, "get key err")
		}
	}

	data, err := json.Marshal(tmp)
	if nil != err {
		log.Println(log.ErrorLog, err.Error())
		return ""
	}
	log.Println(log.WarningLog, "out paras: ", string(data))
	return string(data)
}

func SetCfgList(cfgList CfgListType) {
	for i := 0; i < len(cfgList); i++ {
		if cfgKey, ok := cfgList[i]["key"]; ok {
			if cfgKeyStr, ok := cfgKey.(string); ok {
				if cfgListTimeKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := cfgList[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										if valStr, ok := v["value"].(string); ok {
											if "" != valStr {
												if val, err := strconv.Atoi(valStr); nil == err {
													if unitStr, ok := v["uint"].(string); ok {
														if timeUint, ok := uintTime[unitStr]; ok {
															valNew := CfgVal{Val: intToDuration(val) * timeUint, DefVal: cfgListMap[CfgKey(key)].DefVal,
																cbLists: cfgListMap[CfgKey(key)].cbLists, NeedSave: cfgListMap[CfgKey(key)].NeedSave}
															if cfgListMap[CfgKey(key)].Val != valNew.Val {
																cfgListMap[CfgKey(key)] = valNew

																cfgListMap[CfgKey(key)].cbLists.Exec(valNew.Val, CHANGE_CALL)
															}
														}
													} else {
														log.Println(log.ErrorLog, "get uint err")
													}
												} else {
													log.Println(log.ErrorLog, "string to int err")
												}
											} else {
												log.Println(log.ErrorLog, "value is nil")
											}
										} else {
											log.Println(log.ErrorLog, "value is not string")
										}
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}

							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else if cfgListVuiKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := cfgList[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										if valStr, ok := v["value"].(string); ok {
											if "" != valStr {
												if val, err := strconv.Atoi(valStr); nil == err {
													valNew := CfgVal{Val: val, DefVal: cfgListMap[CfgKey(key)].DefVal,
														cbLists: cfgListMap[CfgKey(key)].cbLists, NeedSave: cfgListMap[CfgKey(key)].NeedSave}
													if cfgListMap[CfgKey(key)].Val != valNew.Val {
														cfgListMap[CfgKey(key)] = valNew

														cfgListMap[CfgKey(key)].cbLists.Exec(valNew.Val, CHANGE_CALL)
													}
												} else {
													log.Println(log.ErrorLog, "string to int err")
												}
											} else {
												log.Println(log.ErrorLog, "value is nil")
											}
										} else {
											log.Println(log.ErrorLog, "value is not string")
										}
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}
							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else if cfgListStrKey.GetKey() == CfgKey(cfgKeyStr) {
					if subNodes, ok := cfgList[i]["subNodes"]; ok {
						for i := 0; i < len(subNodes.([]interface{})); i++ {
							if v, ok := subNodes.([]interface{})[i].(map[string]interface{}); ok {
								if key, ok := v["key"].(string); ok {
									if _, ok := cfgListMap[CfgKey(key)]; ok {
										if valStr, ok := v["value"].(string); ok {
											if "" != valStr {
												valNew := CfgVal{Val: valStr, DefVal: cfgListMap[CfgKey(key)].DefVal,
													cbLists: cfgListMap[CfgKey(key)].cbLists, NeedSave: cfgListMap[CfgKey(key)].NeedSave}
												if cfgListMap[CfgKey(key)].Val != valNew.Val {
													cfgListMap[CfgKey(key)] = valNew

													cfgListMap[CfgKey(key)].cbLists.Exec(valNew.Val, CHANGE_CALL)
												}
											} else {
												log.Println(log.ErrorLog, "value is nil")
											}
										} else {
											log.Println(log.ErrorLog, "value is not string")
										}
									} else {
										log.Println(log.ErrorLog, "get value err")
									}
								} else {
									log.Println(log.ErrorLog, "get key err")
								}
							} else {
								log.Println(log.ErrorLog, "get subNodes arr data err")
							}
						}
					} else {
						log.Println(log.ErrorLog, "get subNodes err")
					}
				} else {
					log.Println(log.ErrorLog, "invalid key:", cfgKeyStr)
				}
			}
		} else {
			log.Println(log.ErrorLog, "get key err")
		}
	}

	log.Printf(log.DebugLog, "%+v\n", cfgListMap)
}

func intToDuration(val int) time.Duration {
	return time.Duration(val)
}
