// 定时协程
// 定时或发通知调用协程函数
package coroutine

import (
	"context"
	"leafstalk/log"
	"sync"
	"time"
)

// TimerRoutine 定时协程类
type TimerRoutine struct {
	name     string
	interval time.Duration
	chEvent  chan struct{}
	wg       sync.WaitGroup
	cancel   context.CancelFunc
	taskFunc func() // 定时执行的任务函数
}

// NewTimerRoutine 创建一个定时协程实例
func NewTimerRoutine(name string, interval time.Duration, taskFunc func()) *TimerRoutine {
	return &TimerRoutine{
		name:     name,
		interval: interval,
		chEvent:  make(chan struct{}, 1),
		taskFunc: taskFunc,
	}
}

// Start 启动定时协程
func (tr *TimerRoutine) Start() {

	ctx, cancel := context.WithCancel(context.Background())
	tr.cancel = cancel

	tr.wg.Add(1)
	go func() {
		defer func() {
			tr.wg.Done()
			log.Infof("TimerRoutine.Start exit %s", tr.name)
		}()
		tr.run(ctx)
	}()
}

// Stop 停止定时协程，等待协程退出
func (tr *TimerRoutine) Stop() {
	tr.cancel()
	tr.wg.Wait()
}

// Notify 发送事件通知，触发任务执行
func (tr *TimerRoutine) Notify() {
	select {
	case tr.chEvent <- struct{}{}:
	default:
	}
}

// run 定时协程的核心逻辑
func (tr *TimerRoutine) run(ctx context.Context) {
	ticker := time.NewTicker(tr.interval)
	defer func() {
		ticker.Stop()
		log.Infof("TimerRoutine.run exit %s", tr.name)
	}()

	safeDo := func() {
		defer func() {
			if err := recover(); err != nil {
				// 处理 panic，例如记录日志
				log.Infof("TimerRoutine recover panic %s: %v", tr.name, err)
			}
		}()
		tr.taskFunc()
	}

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
		case <-tr.chEvent:
		}
		if tr.taskFunc != nil {
			safeDo()
		}
	}
}

func example1() {
	timerRoutine := NewTimerRoutine("MyTimer", time.Second*5, func() {

	})
	timerRoutine.Start()
	timerRoutine.Stop()
}
