package services

import (
	"context"
	"errors"
	"eta/eta_task/models"
	"eta/eta_task/utils"
	"fmt"
	"github.com/beego/beego/v2/task"
	"strconv"
	"strings"
	"time"
)

// EdbTaskNameMap 手工指标定时任务名称map集合
var EdbTaskNameMap map[string]map[string]bool

// EdbTaskNameChannel 手工指标定时任务名称channel
var EdbTaskNameChannel chan string

// EdbTaskStopChannel 手工指标定时任务停止channel
var EdbTaskStopChannel chan string

// EdbTaskRunNum 手工指标定时任务开始次数
var EdbTaskRunNum int

// AddEdbTask 新增手工指标数据录入提醒
func AddEdbTask(cont context.Context) (err error) {
	//失败列表
	failList := make([]string, 0)

	defer func() {
		if len(failList) > 0 {
			fmt.Println("提醒失败:")
			for _, v := range failList {
				fmt.Println(v)
			}

		}
	}()
	list, err := models.GetEdbInfoByFrequencyNotDay()
	if err != nil {
		fmt.Println("查询获取频度非日度 且 提醒时间不为空 的指标数据失败,Err:", err.Error())
	}
	//如果还没有初始化map,那么先初始
	if EdbTaskNameMap == nil {
		EdbTaskNameMap = make(map[string]map[string]bool)
	}
	tmpEdbTaskNameMap := make(map[string]bool)

	// 今天的日期字符串(格式:2021-10-25)
	todayStr := time.Now().Format(utils.FormatDate)

	//当前周的周一与周日
	nowWeekFirstDay := utils.GetNowWeekMonday()
	nowWeekLastDay := utils.GetNowWeekLastDay()

	//当前月的一号与最后一天
	nowMonthFirstDay := utils.GetNowMonthFirstDay()
	nowMonthLastDay := utils.GetNowMonthLastDay()

	//当前季度的第一天与最后一天
	nowQuarterFirstDay := utils.GetNowQuarterFirstDay()
	nowQuarterLastDay := utils.GetNowQuarterLastDay()

	//当前半年的第一天与最后一天
	nowHalfYearFirstDay := utils.GetNowHalfYearFirstDay()
	nowHalfYearLastDay := utils.GetNowHalfYearLastDay()

	// 当前年的第一天与最后一天
	nowYearFirstDay := utils.GetNowYearFirstDay()
	nowYearLastDay := utils.GetNowYearLastDay()

	debugNoticeUserId := 0 //测试环境,需要发送消息的用户
	//测试环境也不发了
	//if utils.RunMode == "debug" {
	//	tmpWxUser, tmpErr := models.GetWxUserByMobile("17634786714")
	//	if tmpErr == nil && tmpWxUser != nil {
	//		//debugNoticeUserId = 44078 //测试环境的话,发送邮箱给颜鹏
	//		debugNoticeUserId = int(tmpWxUser.UserId) //测试环境的话,发送邮箱给嘉豪
	//	}
	//}

	//task.globalTaskManager.adminTaskList
	for _, edb := range list {
		if edb.UserId <= 0 {
			continue //没有配置user_id的话,那么不需要提醒
		}
		tmpEdb := edb            //指标信息
		isNotice := false        //是否需要提醒
		noticeTime := "12:00:00" //提醒时间

		var dataDtTime time.Time
		edbData, tmpErr := models.GetLastEdbdataInfo(tmpEdb.TradeCode)
		if tmpErr != nil {
			if tmpErr.Error() != utils.ErrNoRow() {
				failList = append(failList, fmt.Sprint(tmpEdb.TradeCode, "失败,Err:", tmpErr.Error()))
				continue
			}
		}

		//如果确实是有数据的
		if edbData != nil {
			tmpDataDtTime, _ := time.ParseInLocation(utils.FormatDate, edbData.Dt, time.Now().Location())
			dataDtTime = tmpDataDtTime
		}

		switch tmpEdb.Frequency {
		case "周度":
			modifyDate := nowWeekLastDay //下次更新日期
			if tmpEdb.NoticeTime != "" {
				addDay := 7
				noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
				if len(noticeArr) >= 2 {
					noticeTime = noticeArr[1]
				}
				noticeWeek := noticeArr[0]
				switch noticeWeek {
				case "周一":
					addDay = 1
				case "周二":
					addDay = 2
				case "周三":
					addDay = 3
				case "周四":
					addDay = 4
				case "周五":
					addDay = 5
				case "周六":
					addDay = 6
				case "周日":
					addDay = 7
				}
				modifyDate = modifyDate.AddDate(0, 0, addDay-7)
			}

			//如果正好是提醒日,同时本周没有过记录,那么需要提醒
			if todayStr == modifyDate.Format(utils.FormatDate) && !nowWeekFirstDay.Before(dataDtTime) {
				isNotice = true
			}
		case "月度":
			addDay := 0
			modifyDate := nowMonthLastDay //下次更新日期
			if tmpEdb.NoticeTime != "" {
				strArr := strings.Split(tmpEdb.NoticeTime, "日")
				if len(strArr) >= 2 {
					noticeTime = strArr[1]
				}
				tmpAddDay, tmpErr := strconv.Atoi(strArr[0])
				if tmpErr != nil {
					continue
				}
				addDay = tmpAddDay - 1
				modifyDate = nowMonthFirstDay.AddDate(0, 0, addDay)
			}

			//如果正好是提醒日,同时本月没有过记录,那么需要提醒
			if todayStr == modifyDate.Format(utils.FormatDate) && !nowMonthFirstDay.Before(dataDtTime) {
				isNotice = true
			}
		case "季度":
			//提醒时间
			if tmpEdb.NoticeTime != "" {
				noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
				if len(noticeArr) >= 2 {
					noticeTime = noticeArr[1]
				}
			}
			//每季度更新数据时间
			//如果正好是提醒日(每季度最后一天),同时本季度没有过记录,那么需要提醒
			if todayStr == nowQuarterLastDay.Format(utils.FormatDate) && !nowQuarterFirstDay.Before(dataDtTime) {
				isNotice = true
			}
		case "半年度":
			//提醒时间
			if tmpEdb.NoticeTime != "" {
				noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
				if len(noticeArr) >= 2 {
					noticeTime = noticeArr[1]
				}
			}
			//每半年度更新数据时间
			//如果正好是提醒日(每半年度最后一天),同时本半年度没有过记录,那么需要提醒
			if todayStr == nowHalfYearLastDay.Format(utils.FormatDate) && !nowHalfYearFirstDay.Before(dataDtTime) {
				isNotice = true
			}
		case "年度":
			//提醒时间
			if tmpEdb.NoticeTime != "" {
				noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
				if len(noticeArr) >= 2 {
					noticeTime = noticeArr[1]
				}
			}
			//每年度更新数据时间
			//如果正好是提醒日(每年度最后一天),同时半年度没有过记录,那么需要提醒
			if todayStr == nowYearLastDay.Format(utils.FormatDate) && !nowYearFirstDay.Before(dataDtTime) {
				isNotice = true
			}
		}

		if isNotice {
			taskName := "edb_task_" + todayStr + ":" + fmt.Sprint(tmpEdb.TradeCode)
			//fmt.Println(taskName, ";", tmpEdb.SecName)

			//定时任务
			tmpTaskFunc := func(ctx context.Context) (funcErr error) {
				//方法执行结束后,移除定时任务
				defer func() {
					EdbTaskNameChannel <- taskName
				}()
				// 匿名方法内判断是否发送提醒,因为可能时间到的时候,发现
				funcIsNotice := false
				// 再次获取指标数据详情
				edbData, tmpErr := models.GetLastEdbdataInfo(tmpEdb.TradeCode)
				if tmpErr != nil {
					if tmpErr.Error() != utils.ErrNoRow() {
						funcErr = tmpErr
						return
					}
				}
				if utils.RunMode == "debug" && debugNoticeUserId > 0 {
					tmpEdb.UserId = debugNoticeUserId //测试环境的话,发送邮箱给嘉豪
				}

				//数据过期时间
				var funcDataDtTime time.Time
				//如果确实是有数据的
				if edbData != nil {
					tmpDataDtTime, _ := time.ParseInLocation(utils.FormatDate, edbData.Dt, time.Now().Location())
					funcDataDtTime = tmpDataDtTime
				}

				//提示频度文案
				notifyFrequency := "每日"

				switch tmpEdb.Frequency {
				case "周度":
					notifyFrequency = "每周"
					modifyDate := nowWeekLastDay //下次更新日期
					if tmpEdb.NoticeTime != "" {
						addDay := 7
						noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
						if len(noticeArr) >= 2 {
							noticeTime = noticeArr[1]
						}
						noticeWeek := noticeArr[0]
						switch noticeWeek {
						case "周一":
							addDay = 1
						case "周二":
							addDay = 2
						case "周三":
							addDay = 3
						case "周四":
							addDay = 4
						case "周五":
							addDay = 5
						case "周六":
							addDay = 6
						case "周日":
							addDay = 7
						}
						modifyDate = modifyDate.AddDate(0, 0, addDay-7)
					}

					//如果正好是提醒日,同时本周没有过记录,那么需要提醒
					if todayStr == modifyDate.Format(utils.FormatDate) && !nowWeekFirstDay.Before(funcDataDtTime) {
						funcIsNotice = true
					}
				case "月度":
					notifyFrequency = "每月"
					addDay := 0
					modifyDate := nowMonthLastDay //下次更新日期
					if tmpEdb.NoticeTime != "" {
						strArr := strings.Split(tmpEdb.NoticeTime, "日")
						if len(strArr) >= 2 {
							noticeTime = strArr[1]
						}
						tmpAddDay, tmpErr := strconv.Atoi(strArr[0])
						if tmpErr != nil {
							funcErr = tmpErr
						}
						addDay = tmpAddDay - 1
						modifyDate = nowMonthFirstDay.AddDate(0, 0, addDay)
					}

					//如果正好是提醒日,同时本月没有过记录,那么需要提醒
					if todayStr == modifyDate.Format(utils.FormatDate) && !nowMonthFirstDay.Before(funcDataDtTime) {
						funcIsNotice = true
					}
				case "季度":
					notifyFrequency = "每季度"
					//提醒时间
					if tmpEdb.NoticeTime != "" {
						noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
						if len(noticeArr) >= 2 {
							noticeTime = noticeArr[1]
						}
					}
					//每季度更新数据时间
					//如果正好是提醒日(每季度最后一天),同时本季度没有过记录,那么需要提醒
					if todayStr == nowQuarterLastDay.Format(utils.FormatDate) && !nowQuarterFirstDay.Before(funcDataDtTime) {
						funcIsNotice = true
					}
				case "半年度":
					notifyFrequency = "每半年度"
					//提醒时间
					if tmpEdb.NoticeTime != "" {
						noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
						if len(noticeArr) >= 2 {
							noticeTime = noticeArr[1]
						}
					}
					//每半年度更新数据时间
					//如果正好是提醒日(每半年度最后一天),同时本半年度没有过记录,那么需要提醒
					if todayStr == nowHalfYearLastDay.Format(utils.FormatDate) && !nowHalfYearFirstDay.Before(funcDataDtTime) {
						funcIsNotice = true
					}
				case "年度":
					notifyFrequency = "每年"
					//提醒时间
					if tmpEdb.NoticeTime != "" {
						noticeArr := strings.Split(tmpEdb.NoticeTime, " ")
						if len(noticeArr) >= 2 {
							noticeTime = noticeArr[1]
						}
					}
					//每年度更新数据时间
					//如果正好是提醒日(每年度最后一天),同时半年度没有过记录,那么需要提醒
					if todayStr == nowYearLastDay.Format(utils.FormatDate) && !nowYearFirstDay.Before(funcDataDtTime) {
						funcIsNotice = true
					}
				}

				//fmt.Println(tmpEdb.TradeCode, " funcIsNotice:", funcIsNotice)
				//如果还是要提醒
				if funcIsNotice {
					//用户微信openid列表数据
					openIdList := make([]*models.OpenIdList, 0)

					//获取用户信息
					admin, err := models.GetAdminByAdminId(tmpEdb.UserId)
					if err != nil {
						if err.Error() == utils.ErrNoRow() {
							funcErr = errors.New("openId 列表为空" + strconv.Itoa(tmpEdb.UserId))
							return
						} else {
							return err
						}
					}
					if admin == nil {
						funcErr = errors.New("openId 列表为空" + strconv.Itoa(tmpEdb.UserId))
						return
					}
					//发送消息
					if admin.OpenId == "" {
						funcErr = errors.New("openId 列表为空" + strconv.Itoa(tmpEdb.UserId))
						return
					}
					openIdTemp := new(models.OpenIdList)
					openIdTemp.OpenId = admin.OpenId
					openIdList = append(openIdList, openIdTemp)

					first := "数据录入提醒"
					keyword1 := tmpEdb.SecName + "该更新了"
					keyword2 := notifyFrequency + " " + tmpEdb.NoticeTime
					remark := tmpEdb.SecName + "该更新了"

					err = SendWxMsgWithFrequency(first, keyword1, keyword2, remark, openIdList)
					if err != nil {
						return err
					}
					//发送成功,记录发送日志
					{
						sendRecord := new(models.EdbinfoSendMsgRecord)
						sendRecord.UserId = tmpEdb.UserId
						sendRecord.TradeCode = tmpEdb.TradeCode
						sendRecord.CreateTime = time.Now()
						err = models.AddEdbinfoSendMsgRecord(sendRecord)
						if err != nil {
							return err
						}
					}
				}
				return
			}

			//添加定时任务(没有设置通知时间就不进行定时任务通知了)
			spec := ``
			if noticeTime != "" {
				noticeArr := strings.Split(noticeTime, ":")
				if len(noticeArr) == 3 {
					//spec = ` */20 * * * * * `
					spec = fmt.Sprintf(` %s %s %s * * * `, noticeArr[2], noticeArr[1], noticeArr[0])

					//定时任务开始的时间
					tmpTask := task.NewTask(taskName, spec, tmpTaskFunc)

					task.AddTask(taskName, tmpTask)
					tmpEdbTaskNameMap[taskName] = true
				}
			}

		}
	}

	//将当天的手工指标加入到手工指标池去
	EdbTaskNameMap[todayStr] = tmpEdbTaskNameMap
	//开启协程,用来清除定时任务
	go deleteTask()

	//如果当前定时任务执行次数大于0次,那么需要往手工指标定时任务停止channel写入数据,用来关闭昨天没有执行的的定时任务
	if EdbTaskRunNum > 0 {
		//清除昨天的数据
		EdbTaskStopChannel <- time.Now().AddDate(0, 0, -1).Format(utils.FormatDate)
	}
	//手工指标定时任务开始次数累加
	EdbTaskRunNum++
	return
	//fmt.Println(task.NewMapSorter())
}

// deleteTask 清除已通知的任务
func deleteTask() {
	for {
		select {
		case taskName := <-EdbTaskNameChannel:
			task.DeleteTask(taskName)
			delete(EdbTaskNameMap, taskName)

		case dayStr := <-EdbTaskStopChannel: //收到停止信号,先清除掉那一天的定时任务,
			for taskName := range EdbTaskNameMap[dayStr] {
				task.DeleteTask(taskName)
				delete(EdbTaskNameMap, taskName)
			}
			break
		}
	}
}