package ensureSendUtil

import (
	"fmt"
	"time"

	"goutil/debugUtil"
	"goutil/logUtil"
)

// 负责发送数据的协程
func sendLoop(s sender, closeSignal chan struct{}) {
	defer func() {
		if r := recover(); r != nil {
			logUtil.LogUnknownError(r)
		}
	}()

	for {
		select {
		case <-s.Done():
			closeSignal <- struct{}{}
			return
		case v := <-s.Data():
			if err := s.Send(v); err != nil {
				// 发送失败存入缓存
				s.Cache() <- v
			}
		}
	}
}

// 定时重发失败的数据
func resendLoop(s sender, folder string, closeSignal chan struct{}) {
	defer func() {
		if r := recover(); r != nil {
			logUtil.LogUnknownError(r)
		}
	}()

	// debug模式每秒重试1次
	var delay time.Duration
	if debugUtil.IsDebug() {
		delay = time.Second
	} else {
		delay = time.Minute * 5
	}

	// 定时重发失败数据
	for {
		select {
		case <-s.Done():
			closeSignal <- struct{}{}
			return
		case <-time.After(delay):
			sendCacheData(s, folder)
			loadData(s.(EnsureSender), folder)
		}
	}
}

// 从sender获取失败数据重发
func sendCacheData(s sender, folder string) {
	failed := make([]dataItem, 0)
	length := len(s.Cache())

	defer func() {
		// 用于记录多次失败后放弃发送的数据
		giveUpItems := make(chan dataItem, len(failed))

		for _, v := range failed {
			if v.Count() >= 3 {
				// 失败次数太多的数据准备存放到磁盘中
				giveUpItems <- v
			} else {
				s.Cache() <- v
			}
		}

		giveUpLen := len(giveUpItems)
		if giveUpLen > 0 {
			// 将多次失败的数据保存到文件中
			if folder[len(folder)-1] == '/' {
				folder = folder[:len(folder)-1]
			}
			saveData(giveUpItems, folder+"_giveup")

			if giveUpLen >= 5 {
				log := fmt.Sprintf("ensureSendUtil: 有%d条数据多次发送失败", giveUpLen)
				logUtil.NormalLog(log, logUtil.Error)
			}
		}

		// 输出信息
		log := fmt.Sprintf("ensureSendUtil: 重发%d条数据，失败%d条，存盘%d条\n", length, len(failed), giveUpLen)
		logUtil.NormalLog(log, logUtil.Info)
	}()

	for {
		select {
		case v := <-s.Cache():
			// 重发数据
			if e := s.Send(v); e != nil {
				// 记录失败的数据
				failed = append(failed, v)
			}
		default:
			return
		}
	}
}
