package controller
/*
#include <uvdbus/smart_sound.h>
*/
import "C"
import (
	"context"
	"fmt"
	"math/rand"
	"netease_control_center/globals"
	"netease_control_center/interfaces/eventPoint"
	"netease_control_center/interfaces/log"
	"netease_control_center/interfaces/schedule"
	"netease_control_center/interfaces/vui"
	"netease_control_center/modules/player"
	"netease_control_center/nembd"
	"netease_control_center/nembd/evdev"
	"reflect"
	"time"
)

const (
	devpath                  = "/dev/input/event2"
	KEY_MULTI_PRESS_TIMEDIFF = 200 //ms
)

var (
	KeyMaps = []*KeyBoard{
		MakeAKey(evdev.KEY_MUTE, 3000, 70, KeyResponse),
		MakeAKey(evdev.KEY_HOME, 3000, 70, KeyResponse),
	}

	ctxKeyVol    context.Context    = nil
	cancleKeyVol context.CancelFunc = nil
)

func GetKeyFromMaps(keycode int) *KeyBoard {
	for _, v := range KeyMaps {
		if v.KeyCode == keycode {
			return v
		}
	}

	return nil
}

type KeyCallBkFunc func(keycode int, pressedTimes uint8, longpress bool, insistTime time.Duration)

type KeyBoard struct {
	KeyCode       int
	LongPressTime uint32

	MaxPressedTimes uint8
	HasPressedTimes uint8

	PressedTime time.Time
	ReleaseTime time.Time

	IsPressed  bool
	HasReacted bool

	Timer *time.Timer

	CbFunc KeyCallBkFunc

	DebugTime time.Time
}

func (this *KeyBoard) Init() {
	this.HasPressedTimes = 0
	this.IsPressed = false
	this.HasReacted = false
	this.Timer.Stop()
}

func MakeAKey(keycode int, LongPressTime uint32, MaxPressedTimes uint8, cb KeyCallBkFunc) *KeyBoard {
	var tmp KeyBoard
	tmp.KeyCode = keycode
	tmp.LongPressTime = LongPressTime
	tmp.MaxPressedTimes = MaxPressedTimes
	tmp.CbFunc = cb
	tmp.HasPressedTimes = 0
	tmp.IsPressed = false
	tmp.HasReacted = false
	tmp.Timer = time.NewTimer(0)
	<-tmp.Timer.C
	return &tmp
}

func KeyResponse(keycode int, pressedTimes uint8, longpress bool, insistTime time.Duration) {
	if globals.OTAStatus_begin == globals.CurOTAStatus {
		log.Println(log.WarningLog, "ignore key because of ota begin")
		return
	}

	log.Println(log.DebugLog, "keycode:", keycode, "  presstimes:", pressedTimes, "  longpress:", longpress, " insisttime:", insistTime)

	switch keycode {
	case evdev.KEY_HOME:
		if longpress {
			if globals.KeyVolTest {
				if nil != cancleKeyVol {
					cancleKeyVol()
					cancleKeyVol = nil
				} else {
					ctxKeyVol, cancleKeyVol = context.WithCancel(context.Background())
					volCtrlTest(ctxKeyVol)
				}

				return
			}
			if globals.WifiSwitch != globals.WifiSwitch_On {
				schedule.SendSCmd(schedule.SCMD_SuperTask_Exit_btOnWifiOff)
				return
			}
			//wifi paring
			schedule.SendSCmd(schedule.SCMD_SuperTask_System_WifiParing)
			eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "wifi paring", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})
		} else {
			switch pressedTimes {
			case 1:
				if schedule.IsCurPlayerInterrupt() == false &&
					(schedule.GetCurPlayerId() != globals.PlayerType_Wifi ||
						!globals.LocalMusicList[globals.CUR_MUSIC_LIST].IsNil()) { //如果当前播放列表为空，按键播放无效
					if schedule.IsCurPlayerPlaying() == true {
						player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Scaozuofankui001.GetPath())
						eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "pause", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})
					} else {
						eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "play", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})
					}
					eventPoint.SetEpOsSouce("F141", eventPoint.EpOs_Device)
					schedule.SendSCmd(schedule.SCMD_MusicPlayer_PlayOrPause)
				} else {
					eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "do nothing", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})
				}
				schedule.SendSCmd(schedule.SCMD_KeyInterrupt)

			case 2:
				if globals.CurBootState == globals.BootStage_WIFIPARING || globals.CurBootState == globals.BootStage_BACKUPSYSTEM_WIFIPARING {
					schedule.SendSCmd(schedule.SCMD_SuperTask_System_WifiModeChange_AP_BT)
					eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "pressedtime": insistTime.Nanoseconds() / 1e6, "net": true, "status": "ap/ble wifi paring", "longpress": longpress})
				} else {
					if schedule.CheckTaskActive(schedule.TaskLevel_SystemService) == false {
						log.Println(log.ErrorLog, "come into mic control!!!")
						player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Scaozuofankui001.GetPath())
						if globals.IsMicClose == true {
							//globals.CurVboxVolSt.MuteMic = false

							SetMicClose(false, globals.WhoCLoseMic_User, true)
							time.Sleep(100 * time.Millisecond)
							player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Mic_Open.GetPath())
						} else {
							//globals.CurVboxVolSt.MuteMic = true

							SetMicClose(true, globals.WhoCLoseMic_User, true)
							if GetCurVoiceStatus() != globals.VoiceStatus_IDLE {
								VoiceEndSession()
								UpdateVoiceStatus(globals.VoiceStatus_IDLE)
							}
							time.Sleep(100 * time.Millisecond)
							player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Mic_Close.GetPath())
						}
						eventPoint.EpRecord("H111", map[string]interface{}{"pressedtime": insistTime.Nanoseconds() / 1e6, "status": globals.IsMicClose, "net": false})
					} else {
						log.Println(log.DebugLog, "Currently s task run, ignore mic disable command!")
						eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "do nothing", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})
					}
				}
				schedule.SendSCmd(schedule.SCMD_KeyInterrupt)
				//log.Println(log.DebugLog, "Continue session!")
				//schedule.SendSCmd(schedule.SCMD_SuperTask_Voice_ContinuSession)
				//eventPoint.EpRecord("H411", map[string]interface{}{"pressedTimes": pressedTimes, "status": "continue session", "pressedtime": insistTime.Nanoseconds() / 1e6, "net": (globals.CurBootState == globals.BootStage_WIFIPARING), "longpress": longpress})

			case 3:
				//player.TestInterfaceForKey(player.NEW_TOP_TYPE)
				CopyLogfiles()
				//schedule.PlayNoticeAsync(globals.AdSrcType_TTS, "日志已保存", globals.CONST_AUDIO_ID, false, nil, nil)
			case 4:
				//if schedule.GetCurScheduleDomain().IsMusicDomain() == false {
				//	log.Println(log.DebugLog, "Not in music mode, do nothing!")
				//	return
				//}
				////wifi switch
				//switch globals.WifiSwitch {
				//case globals.WifiSwitch_On:
				//	log.Println(log.DebugLog, "Turn off wifi")
				//	globals.WifiSwitch = globals.WifiSwitch_Offing
				//	SendWifiCmd(uint32(C.CMD_WIFI_OFF))
				//	SetInternetConnect(false, "user force")
				//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Exit_BtOnWifiOff.GetPath())
				//
				//case globals.WifiSwitch_Off:
				//	log.Println(log.DebugLog, "Turn on wifi")
				//	globals.WifiSwitch = globals.WifiSwitch_Oning
				//	SendWifiCmd(uint32(C.CMD_WIFI_ON))
				//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Enter_BtOnWifiOff.GetPath())
				//
				//case globals.WifiSwitch_Oning:
				//	log.Println(log.DebugLog, "Wifi is oning!")
				//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Enter_BtOnWifiOff.GetPath())
				//
				//case globals.WifiSwitch_Offing:
				//	log.Println(log.DebugLog, "Wifi is offing!")
				//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Exit_BtOnWifiOff.GetPath())
				//}
				//player.TestInterfaceForKey(player.HOT_TOP_TYPE)
			case 5:
				//player.TestInterfaceForKey(player.CREATE_LISTS_TYPE)
			}
		}
		schedule.SendSCmd(schedule.SCMD_SChedule)

	case evdev.KEY_MUTE:
		if longpress {

		} else {
			switch pressedTimes {
			case 1:
				VboxTagTestSongSimilar()
			case 2:
				VboxCardTestTag()
				//CopyLogfiles()
				//schedule.PlayNoticeAsync(globals.AdSrcType_TTS, "日志已保存", globals.CONST_AUDIO_ID, false, nil, nil)

				//MakeAlarmDataTest()
				//go GifShow()
				//go led_mcu.InitMcu()
				//led_mcu.LightAllLedDisplay()
				//led_mcu.LightGifTest()
				//led_mcu.DirectLedControl(led_mcu.GUIDE_EFFECT_ID_VOICE_WAKEUP, led_mcu.GUIDE_ACTION_START, 6, []byte{})
				//led_mcu.LightImage("/tmp/ihw")
				//go OTACheckNewVersion()
				//bt.BlueTooth_Init()
				//wifi.TestAP()
			}
		}
	}
}

func MultiKeySelectRoutine() {
	keytimers := make([]reflect.SelectCase, 0, 2)
	for _, v := range KeyMaps {
		sc := reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(v.Timer.C)}
		keytimers = append(keytimers, sc)
	}
	for {
		no, _, ok := reflect.Select(keytimers)
		if ok && no < len(KeyMaps) {
			key := KeyMaps[no]
			insistTime := time.Now().Sub(key.ReleaseTime)

			//long press
			if insistTime >= time.Millisecond*time.Duration(key.LongPressTime) {
				go key.CbFunc(key.KeyCode, 0, true, insistTime)
				key.HasReacted = true
			} else {
				if key.HasPressedTimes <= key.MaxPressedTimes {
					go key.CbFunc(key.KeyCode, key.HasPressedTimes, false, insistTime)
				} else {
					//do nothing
					fmt.Println("Beyond key touch max value")
				}
				key.Init()
			}
		}
	}
}

func TriggerKey(keycode int, isPress bool) {
	key := GetKeyFromMaps(keycode)
	if key == nil {
		return
	}

	if isPress {
		key.Timer.Reset(time.Duration(key.LongPressTime) * time.Millisecond)
		key.PressedTime = time.Now()
		key.IsPressed = true
		key.HasPressedTimes++

		//justdebug
		log.Println(log.DebugLog, "Pressed time: ", time.Now().Sub(key.DebugTime).Seconds())
	} else {
		key.IsPressed = false
		key.ReleaseTime = time.Now()
		if key.HasReacted {
			key.Init()
			return
		}
		if key.MaxPressedTimes == 1 {
			key.Timer.Reset(0)
		} else {
			key.Timer.Reset(KEY_MULTI_PRESS_TIMEDIFF * time.Millisecond)
		}

		//justdebug
		key.DebugTime = time.Now()
	}
}

func KeyApp() error {
	dev, err := evdev.Open(globals.GetCurPlatformConfig().InputKeyPath)
	if err != nil {
		return err
	}

	for {
		if event, err := dev.ReadOne(); err == nil && event.Type == uint16(evdev.EV_KEY) {

			var isPress bool
			if event.Value == 1 {
				isPress = true
			} else {
				isPress = false
			}
			TriggerKey(int(event.Code), isPress)
			switch event.Code {
			case evdev.KEY_VOLUMEUP:
				val, _ := VolInc(1)
				ShowVolumeLed()
				//if schedule.IsCurPlayerPlaying() == false {
				//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Volume.GetPath())
				//}

				//fmt.Println("Cur vol:", vol)
				//volBroadCast()
				fmt.Println("Cur vol:", val)
				eventPoint.SetEpOsSouce("H511", eventPoint.EpOs_Device)

			case evdev.KEY_VOLUMEDOWN:
				val, _ := VolDec(1)
				ShowVolumeLed()
				//if schedule.IsCurPlayerPlaying() == false {
				//player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Volume.GetPath())
				//}
				fmt.Println("Cur vol:", val)
				eventPoint.SetEpOsSouce("H511", eventPoint.EpOs_Device)

				//volBroadCast()
			case evdev.KEY_MUTE:
				// todo CurVboxVolSt.Mute　变量的处理
				break
				v, err := nembd.DigitalRead("MUTE")
				log.Println(log.DebugLog, v, err)
				if err != nil {
					continue
				}
				switch {
				case v > 0:
					v = 0
				case v == 0:
					v = 1
				}
				nembd.DigitalWrite("MUTE", v)

			case evdev.KEY_HOME:
				//
			default:
				log.Printf(log.WarningLog, "Unknow key,%d\n", event.Code)
			}
		}
	}

}

func volCtrlTest(ctx context.Context) {
	var inc bool = false
	var cnt int = 0
	go func() {
		for {
			select {
			case <-ctx.Done():
				log.Printf(log.WarningLog, "keyVol test over.\n")
				return
			default:

			}
			val := volIncDec(inc)
			if val <= 8 {
				inc = true
			} else if val >= 12 {
				inc = false
			}
			cnt++
			if cnt < 50 {
				timePeriod := rand.Intn(50) + 1
				time.Sleep(time.Duration(timePeriod) * time.Millisecond)
			} else {
				cnt = 0
				time.Sleep(5 * time.Second)
			}
		}

	}()
}

func volIncDec(inc bool) int {
	var val int
	if inc {
		val, _ = VolInc(1)
	} else {
		val, _ = VolDec(1)
	}

	ShowVolumeLed()
	//if schedule.IsCurPlayerPlaying() == false {
	//	player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Volume.GetPath())
	//}

	fmt.Println("Cur vol:", val)
	return val
}
