package controller

import (
	"context"
	"fmt"
	"netease_control_center/globals"
	"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"
	"netease_control_center/modules/player"
	"netease_control_center/nembd/controller/adau1761"
	"sync"
	"time"
)

const (
	servicename_remind  = "remind_service"
	remind_repeat_times = 2
)

var (
	remindtaskhd TaskHd
	remindCh     = make(chan globals.DbusAlarmRemind, 50)

	remindIsRunning = false

	lock_remind sync.Mutex

	remindCtx, remindCtxCancel = context.WithCancel(context.Background())

	remindPreVol int
)

func remindTask_Interrupt(ByWho string) {
	lock_remind.Lock()
	defer lock_remind.Unlock()

	defer func() {
		if err := recover(); err != nil {
			log.Println(log.ErrorLog, err)
		}
	}()

	if remindIsRunning == true && ByWho == ModuleName_Key {
		player.SoundEffectPlayCmd(globals.CMD_SE_PLAY, vui.SoundNotice_Scaozuofankui001.GetPath())
	}

	remindCtxCancel()

	if remindIsRunning == true {
		remindDoExit()
	}
}

func clearRemindChan() {
Loop:
	for {
		select {
		case <-remindCh:
		default:
			break Loop
		}
	}
}

func remindDoExit() {
	log.Println(log.DebugLog, "Do remind exit!")
	clearRemindChan()

	remindIsRunning = false
	restoreRemindVolume()
	led_mcu.DirectLedClear(atservice.GUIDE_EFFECT_ID_EXEC_CMD)
	vui.IconLed_IconTixing001.Clear()

	if remindIsRunning == true {
		restoreRemindVolume()
		led_mcu.DirectLedClear(atservice.GUIDE_EFFECT_ID_EXEC_CMD)
		vui.IconLed_IconTixing001.Clear()
	}

	remindIsRunning = false
	SendSCmd(SCMD_SChedule)
}

func ttsVui(rmind globals.DbusAlarmRemind) string {
	var tmp string
	intervalname := vui.GetCurDayIntervalNameByHour(rmind.ComingTime.Hour())
	if len(rmind.Tts) == 0 {
		tmp = fmt.Sprintf("现在是%s%s，你有个提醒", intervalname.String(), rmind.ComingTime.Format("3:04"))
	} else {
		tmp = fmt.Sprintf("现在是%s%s，你有个%s的提醒",
			intervalname.String(), rmind.ComingTime.Format("3:04"),
			rmind.Tts)
	}

	return tmp
}

func playRemind(rmind globals.DbusAlarmRemind) {
	log.Printf(log.DebugLog, "Will play remind:%+v\n", rmind)
	vui.IconLed_IconTixing001.Show()
	led_mcu.DirectLedControl(atservice.GUIDE_EFFECT_ID_EXEC_CMD, atservice.GUIDE_ACTION_START, 0, []byte{})

	remindIsRunning = true

	PlayNoticeAsync(globals.AdSrcType_FILE, vui.SoundNotice_Stixing001.GetPath(), globals.CONST_AUDIO_ID, false, remindCtx, func(id uint32, reason NoticeStopReason) {
		if reason.IsStart() {
			return
		}

		if reason == NoticeStopReason_Complete {
			ttsType := globals.AdSrcType_TTS
			ttsContent := ttsVui(rmind)

			if globals.InternetConnect == false {
				ttsType = globals.AdSrcType_FILE
				ttsContent = vui.SoundNotice_TixingInternetDown.GetPath()
			}

			PlayNoticeAsync(ttsType, ttsContent, globals.CONST_AUDIO_ID, true, remindCtx, func(id uint32, reason NoticeStopReason) {
				if reason.IsStart() {
					return
				}

				lock_remind.Lock()
				defer lock_remind.Unlock()
				if (reason == NoticeStopReason_Complete || reason == NoticeStopReason_Error) && remindtaskhd.GetTaskStatus() == TaskStatus_Running {
					if rmind.RingTimes < remind_repeat_times-1 {
						rmind.RingTimes++
						playRemind(rmind)
					} else {
						toastRemind()
					}
				} else {
					//do nothing, current may be cancel
					remindDoExit()
				}
			})
		} else {
			//do nothing, current may be cancel
			remindDoExit()
		}
	})
}

func toastRemind() {
_begin:
	select {
	case rmind := <-remindCh:
		log.Printf(log.DebugLog, "Begin to toast remind:%+v\n", rmind)
		if time.Now().Local().Sub(rmind.ComingTime) <= time.Minute {
			playRemind(rmind)
		} else {
			log.Printf(log.DebugLog, "Current remind has expired 1 min,not play:%+v\n", rmind)
			goto _begin
		}
	default:
		remindDoExit()
	}
}

func backupRemindvolume() {
	log.Println(log.DebugLog, "Backup remind volume!")
	time.Sleep(20 * time.Millisecond)
	remindPreVol, _ = adau1761.GetVol()
	if remindPreVol < globals.DefaultVol.GetCfgListVui() {
		VolSet(globals.DefaultVol.GetCfgListVui())
	} else {
		VolSet(remindPreVol)
	}

	tmpvol, _ := adau1761.GetVol()
	log.Println(log.DebugLog, "Remind set vol:", tmpvol)
}

func restoreRemindVolume() {
	log.Println(log.DebugLog, "Restore volume!")
	curvol, _ := adau1761.GetVol()
	if curvol != globals.DefaultVol.GetCfgListVui() && remindPreVol != curvol {
		log.Println(log.DebugLog, "Mybe volume change, do nothing!", remindPreVol, curvol, globals.DefaultVol.GetCfgListVui())
	} else {
		log.Println(log.DebugLog, "Set pre volume:", remindPreVol)
		vol, err := VolSet(remindPreVol)
		log.Println(log.DebugLog, "Set volume result:", vol, err)
	}
}

func remindTask_exec(canExec bool, scmd SCMD, arg ...interface{}) {
	defer func() {
		if err := recover(); err != nil {
			log.Println(log.ErrorLog, err)
		}
	}()

	switch scmd {
	case SCMD_SuperTask_Remind_Ring:
		if remind, ok := arg[0].(globals.DbusAlarmRemind); ok == true {
			lock_remind.Lock()
			defer lock_remind.Unlock()

			go TellServerRemindRing(remind.Id, ttsVui(remind))

			if remindIsRunning == false {
				remindCtxCancel()
				remindCtx, remindCtxCancel = context.WithCancel(context.Background())
			}

			select {
			case remindCh <- remind:
			default:
				<-remindCh
				remindCh <- remind
			}

			if canExec == true {
				if remindIsRunning == false {
					backupRemindvolume()
					toastRemind()
				}
			}
		}
	}
}

func remindTask_Resume() {
	//do nothing
	lock_remind.Lock()
	defer lock_remind.Unlock()
	remindIsRunning = true
	backupRemindvolume()
	toastRemind()
}

func RemindTaskinit() {
	var tmp RegistedTask
	var err error

	tmp.Interrupt = remindTask_Interrupt

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

	tmp.IsActive = func() bool {
		return len(remindCh) > 0 || remindIsRunning == true
	}

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

	tmp.Resume = remindTask_Resume

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

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

	tmp.Do = remindTask_exec
	tmp.CanBeInterruptByKey = func() bool {
		return true
	}

	tmp.Debug = func() string {
		var tmp string
		tmp += fmt.Sprintf("  Remind Chan len:%d\n", len(remindCh))
		tmp += fmt.Sprintln("  IsRunning:", remindIsRunning)

		return tmp
	}

	if err, remindtaskhd = 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())
	}
}
