package controller

/*
#include <uvdbus/smart_sound.h>
#include <uvdbus/ota.h>
*/
import "C"
import (
	"context"
	"encoding/json"
	"netease_control_center/globals"
	"netease_control_center/interfaces/http"
	"netease_control_center/interfaces/log"
	. "netease_control_center/interfaces/schedule"
	"netease_control_center/interfaces/vui"
	"netease_control_center/modules/hardware/led_mcu"
	"netease_control_center/modules/hardware/mcu_leds/atservice"
	"runtime/debug"
	"sync"
	"time"
)

const (
	modename_iotwifiparing = "iot_wifiparing_service"
)

var (
	iot_hd                         TaskHd
	iot_lock                       sync.Mutex
	iot_running                    = false
	iot_is_exiting                 = false
	iot_timeout_exit               *time.Timer
	iot_do_once                    sync.Once
	iot_contex, iot_context_cancel = context.WithCancel(context.Background())
	iot_stage_before_find_dev      = true
)

const (
	iot_tts_enter         = "正在为您扫描周围的智能设备,请耐心等待一下哦"
	iot_tts_not_found_dev = "抱歉，没有找到附近的智能设备,请检查设备是否在配网状态哦"
	iot_tts_fail          = "抱歉，连接设备失败检查一下网络状况稍后再试哦"
	iot_tts_found_dev     = "已为你找到智能设备，现在开始联网，请稍等"
)

func iot_Interrupt(ByWho string) {
	iot_lock.Lock()
	defer iot_lock.Unlock()

	if iot_running {
		iot_wifiparing_exit()
		time.Sleep(time.Millisecond * 20)
		log.Println(log.DebugLog, "Iot wifi paring interruptted!")
	}
}

func iot_Resume() {
	log.Println(log.DebugLog, "Should not come here!")
	iot_lock.Lock()
	defer iot_lock.Unlock()
	iot_wifiparing_exit()
}

func iotTask_exec(canExec bool, scmd SCMD, arg ...interface{}) {
	if canExec && scmd == SCMD_SuperTask_Enter_IOT_WifiParing {
		iot_lock.Lock()
		defer iot_lock.Unlock()
		//todo if is paring
		if iot_running {
			log.Println(log.DebugLog, "Iot already is in wifi paring now!")
			return
		}
		iot_running = true
		iot_is_exiting = false
		iot_stage_before_find_dev = true
		iot_context_cancel()
		iot_do_once = sync.Once{}
		iot_contex, iot_context_cancel = context.WithCancel(context.Background())
		SendEventnByYunxinWithRid(DeviceEventType_IotWifiParing, DeviceEventAction_Start, "", false, nil)
		globals.ResetBroadCastTimer()
		//begin to show led
		led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_NET_MODE, atservice.GUIDE_ACTION_START, 0, []byte{})
		vui.IconLed_Wifiparing_Ap.Show()
		//begin to toast tts
		PlayNoticeAsync(globals.AdSrcType_FILE, vui.SoundNotice_IOT_Finding.GetPath(), globals.CONST_AUDIO_ID, false, iot_contex, nil)
		http.InformMsgToServer(http.Type_Inform_TtsDelay, iot_tts_enter)
		SendWifiCmd(uint32(C.CMD_WIFI_BL_CONF))

		iot_timeout_exit = time.AfterFunc(60*time.Second, func() {
			log.Println(log.DebugLog, "Iot timeout, do exit!")
			iot_lock.Lock()
			defer iot_lock.Unlock()

			if iot_is_exiting == true {
				log.Println(log.DebugLog, "IOT is exiting, do nothing!")
				return
			}
			iot_is_exiting = true

			PlayNoticeAsync(globals.AdSrcType_FILE, vui.SoundNotice_IOT_NotFound.GetPath(), globals.CONST_AUDIO_ID, false, iot_contex, func(id uint32, reason NoticeStopReason) {
				iot_lock.Lock()
				defer iot_lock.Unlock()
				if iot_running == false {
					return
				}
				if reason.IsStart() {
					led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_EXEC_CMD, atservice.GUIDE_ACTION_START, 0, []byte{})
					vui.IconLed_VoiceExecResult.Show()
				}
				if reason.IsStop() {
					iot_wifiparing_exit()
				}
			})
			http.InformMsgToServer(http.Type_Inform_TtsDelay, iot_tts_not_found_dev)
		})
	} else {
		log.Println(log.DebugLog, modename_iotwifiparing, "can not run.", canExec, scmd)
	}
}

func iot_wifiparing_exit() {
	if iot_running == true {
		debug.PrintStack()
		log.Println(log.DebugLog, "Do exit iot wifi paring!")
		iot_running = false
		SendEventnByYunxinWithRid(DeviceEventType_IotWifiParing, DeviceEventAction_End, "", false, nil)
		if iot_timeout_exit != nil {
			iot_timeout_exit.Stop()
		}
		iot_context_cancel()

		//turn off leds/icon
		//tell wifi module stop
		SendWifiCmd(uint32(C.CMD_WIFI_BL_CONF_ABORT))
		led_mcu.DirectLedClear(atservice.GUIDE_EFFECT_ID_EXEC_CMD)
		led_mcu.DirectLedClear(atservice.GUIDE_EFFECT_ID_NET_MODE)
		vui.IconLed_Clear.Show()
		SendSCmd(SCMD_SChedule)

		//2s after broad vbox status
		globals.SetBroadCastTimer(2*time.Second)
	} else {
		log.Println(log.DebugLog, "Iot has exit, do nothing!")
	}
}

func iot_connect_fail_toast() {
	if iot_is_exiting {
		debug.PrintStack()
		log.Println(log.DebugLog, "Iot is exiting, do nothing!")
		return
	}
	iot_is_exiting = true
	if iot_timeout_exit != nil {
		iot_timeout_exit.Stop()
	}
	debug.PrintStack()
	var tts string
	if iot_stage_before_find_dev == true {
		tts = vui.SoundNotice_IOT_NotFound.GetPath()
	} else {
		tts = vui.SoundNotice_IOT_ConnectedFail.GetPath()
	}
	PlayNoticeAsync(globals.AdSrcType_FILE, tts, globals.CONST_AUDIO_ID, false, iot_contex, func(id uint32, reason NoticeStopReason) {
		iot_lock.Lock()
		defer iot_lock.Unlock()
		if iot_running == false {
			return
		}

		if reason.IsStart() {
			led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_EXEC_CMD, atservice.GUIDE_ACTION_START, 0, []byte{})
			vui.IconLed_VoiceExecResult.Show()
		}
		if reason.IsStop() {
			iot_wifiparing_exit()
		}
	})
	http.InformMsgToServer(http.Type_Inform_TtsDelay, iot_tts_fail)
}

func iotDbusMsg(buscmd uint32, arg string) {
	iot_lock.Lock()
	defer iot_lock.Unlock()

	if iot_running == false || iot_is_exiting == true {
		SendWifiCmd(uint32(C.CMD_WIFI_BL_CONF_ABORT))
		log.Println(log.DebugLog, "Current iot wifi service is stop , do not wifi paring!")
		return
	}

	switch buscmd {
	case uint32(C.CMD_WIFI_BL_CONF_FAILED):
		iot_connect_fail_toast()

	case uint32(C.CMD_WIFI_BL_DEV_INFO_NTF):
		var req http.HttpReqDevDiscovery
		var rsp http.HttpRspDeviceDiscovery
		if err := json.Unmarshal([]byte(arg), &req); err == nil {
			if code, _, err := http.HttpPostAuto(req, &rsp); code == int(globals.ERR_SUCCESS) && err == nil {
				if data, err := json.Marshal(rsp); err == nil {
					//if len(rsp.Tts) > 0 {
					//	PlayNoticeAsync(globals.AdSrcType_TTS, rsp.Tts, globals.CONST_AUDIO_ID, false, iot_contex, nil)
					//}
					//if iot_timeout_exit != nil {
					//	iot_timeout_exit.Stop()
					//	iot_timeout_exit = time.AfterFunc(time.Second*60, func() {
					//		iot_connect_fail_toast()
					//	})
					//}
					SendWifiData(uint32(C.CMD_WIFI_BL_CLOUD_CHALLENGE_SIGNATURE), data)
				} else {
					log.Println(log.DebugLog, "json marsh err:", err)
					iot_connect_fail_toast()
				}
			} else {
				log.Println(log.ErrorLog, "Http req fail, code:", code, "err:", err)
				//iot_connect_fail_toast()
			}
		} else {
			log.Println(log.DebugLog, "CMD_WIFI_BL_DEV_INFO_NTF decode data err:", err)
			iot_connect_fail_toast()
		}

	case uint32(C.CMD_WIFI_BL_DEV_SIGNATURE):
		var req http.HttpReqDeviceSharedKey
		var rsp http.HttpRspDeviceSharedKey
		if err := json.Unmarshal([]byte(arg), &req); err == nil {
			if code, _, err := http.HttpPostAuto(req, &rsp); code == int(globals.ERR_SUCCESS) && err == nil {
				if data, err := json.Marshal(rsp); err == nil {
					SendWifiData(uint32(C.CMD_WIFI_BL_CLOUD_SHAREDKEY), data)
				} else {
					log.Println(log.DebugLog, "CMD_WIFI_BL_CLOUD_SHAREDKEY json marsh err:", err)
					iot_connect_fail_toast()
				}
			} else {
				log.Println(log.ErrorLog, "CMD_WIFI_BL_CLOUD_SHAREDKEY Http req fail, code:", code, "err:", err)
				iot_connect_fail_toast()
			}
		} else {
			log.Println(log.DebugLog, "CMD_WIFI_BL_CLOUD_SHAREDKEY decode data err:", err)
			iot_connect_fail_toast()
		}

	case uint32(C.CMD_WIFI_BL_DEV_TOKEN):
		var req http.HttpReqDeviceRegiste
		if err := json.Unmarshal([]byte(arg), &req); err == nil {
			var rsp http.HttpRspDeviceRegiste
			if code, _, _ := http.HttpPostAuto(req, &rsp); code == int(globals.ERR_SUCCESS) {
				PlayNoticeAsync(globals.AdSrcType_TTS, rsp.Tts, globals.CONST_AUDIO_ID, false, iot_contex, func(id uint32, reason NoticeStopReason) {
					if reason == NoticeStopReason_Error && iot_is_exiting == false {
						PlayNoticeAsync(globals.AdSrcType_FILE, vui.SoundNotice_IOT_Finded.GetPath(), globals.CONST_AUDIO_ID, false, iot_contex, nil)
					}
				})
				iot_stage_before_find_dev = false
				SendWifiCmd(uint32(C.CMD_WIFI_BL_DEV_TOKEN_BOUND))
				if iot_timeout_exit != nil {
					iot_timeout_exit.Stop()
				}
				iot_timeout_exit = time.AfterFunc(60*time.Second, func() {
					iot_lock.Lock()
					defer iot_lock.Unlock()

					iot_connect_fail_toast()
				})
			} else {
				log.Println(log.DebugLog, "Request server error! exit")
				iot_connect_fail_toast()
			}

			//var checkfunc func()
			//
			//checkfunc = func() {
			//	log.Println(log.DebugLog, "Begin to check iot wifi paring status, ", iot_running)
			//	if iot_running == true {
			//		var rsp http.HttpRspDeviceRegiste
			//		if code, _, _ := http.HttpPostAuto(req, &rsp); code == int(globals.ERR_SUCCESS) {
			//			SendWifiCmd(uint32(C.CMD_WIFI_BL_DEV_TOKEN_BOUND))
			//			if iot_timeout_exit != nil {
			//				iot_timeout_exit.Stop()
			//			}
			//
			//
			//		} else {
			//			log.Println(log.DebugLog, "Request server error! 2s after retry")
			//			time.AfterFunc(time.Second*2, checkfunc)
			//		}
			//	} else {
			//		log.Println(log.DebugLog, "Exit do noting! iot stataus:", iot_running)
			//	}
			//}

			//go iot_do_once.Do(checkfunc)
		} else {
			log.Println(log.DebugLog, "CMD_WIFI_BL_DEV_TOKEN json err:", err)
			iot_connect_fail_toast()
		}
	}
}

func Iot_Wifiparing_end(tts string) {
	iot_lock.Lock()
	defer iot_lock.Unlock()
	if iot_running == true {
		if iot_timeout_exit != nil {
			iot_timeout_exit.Stop()
		}
		if iot_is_exiting == true {
			log.Println(log.DebugLog, "iot is exitting, do nothing!")
			return
		}
		iot_is_exiting = true

		if len(tts) == 0 {
			tts = "与智能设备连接成功，操作方式已经发送至手机，快打开手机APP进入智能家居页面学习怎么操作吧～"
		}
		PlayNoticeAsync(globals.AdSrcType_TTS, tts, globals.CONST_AUDIO_ID, true, iot_contex, func(id uint32, reason NoticeStopReason) {
			iot_lock.Lock()
			defer iot_lock.Unlock()
			if iot_running == false {
				return
			}

			if reason == NoticeStopReason_Error {
				PlayNoticeAsync(globals.AdSrcType_FILE, vui.SoundNotice_IOT_ConnectedSuccess.GetPath(), globals.CONST_AUDIO_ID, true, iot_contex, func(id uint32, reason NoticeStopReason) {
					iot_lock.Lock()
					defer iot_lock.Unlock()
					if iot_running == false {
						return
					}

					if reason.IsStart() {
						led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_EXEC_CMD, atservice.GUIDE_ACTION_START, 0, []byte{})
						vui.IconLed_VoiceExecResult.Show()
					} else if reason.IsStop() {
						iot_wifiparing_exit()
					}

				})

				return
			}

			if reason.IsStart() {
				led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_EXEC_CMD, atservice.GUIDE_ACTION_START, 0, []byte{})
				vui.IconLed_VoiceExecResult.Show()
			} else if reason.IsStop() {
				iot_wifiparing_exit()
			}
		})
		http.InformMsgToServer(http.Type_Inform_TtsDelay, tts)
	}
}

func Iot_Wifiparing_disconnect() {
	iot_lock.Lock()
	defer iot_lock.Unlock()

	if iot_running == true {
		log.Println(log.DebugLog, "In wifi paring but internet is down!")
		iot_wifiparing_exit()
		ToastNetworkError(false)
	}
}

func IOTTaskinit() {
	var tmp RegistedTask
	var err error

	tmp.Interrupt = iot_Interrupt

	tmp.GetName = func() string {
		return modename_iotwifiparing
	}

	tmp.IsActive = func() bool {
		return iot_running
	}

	tmp.GetTaskLevel = func() TaskLevel {
		return TaskLevel_IotWifiParingService
	}

	tmp.Resume = iot_Resume

	tmp.GetSupportedSCmd = func() []SCMD {
		return []SCMD{SCMD_SuperTask_Enter_IOT_WifiParing}
	}

	tmp.GetScheduleDomain = func() ScheduleDomain {
		return ScheduleDomain_IotWifiParing
	}

	tmp.Do = iotTask_exec
	tmp.CanBeInterruptByKey = func() bool {
		return false
	}

	if err, iot_hd = RegisteSTask(tmp); err == nil {
		log.Printf(log.DebugLog, "Registe %s task successfully!!\n", tmp.GetName())
	} else {
		log.Printf(log.ErrorLog, "Registe %s task fail!!\n", tmp.GetName())
	}
}
