package trigger

import (
	"context"

	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/zhouqiang-cl/cron"
)

// CronTrigger is cron trigger
type CronTrigger struct {
	ctx  context.Context
	jobs map[int64][]int64
	cron *cron.Cron
}

// NewCronTrigger creates cron trigger
func NewCronTrigger(ctx context.Context) Interface {
	cronTrigger := &CronTrigger{
		ctx:  ctx,
		jobs: make(map[int64][]int64),
	}
	cronTrigger.cron = cron.New()
	cronTrigger.cron.Start()

	go cronTrigger.run()
	return cronTrigger
}

func (c *CronTrigger) run() {
	log.Info("cron trigger start !")

	defer func() {
		log.Info("cron trigger stop !")
		c.Stop()
	}()

	for {
		select {
		case <-c.ctx.Done():
			return
		}
	}
}

// Stop stops cron trigger
func (c *CronTrigger) Stop() {
	c.cron.Stop()
}

// AddJob adds cronjob
func (c *CronTrigger) AddJob(ruleValue string, fn func(), jobID int64) error {
	entityID, err := c.cron.AddFunc(ruleValue, fn)
	if err != nil {
		return errors.Trace(err)
	}

	c.jobs[jobID] = append(c.jobs[jobID], entityID)
	return nil
}

// DelJob deletes cronjob
func (c *CronTrigger) DelJob(jobID int64) error {
	entityIDs, exist := c.jobs[jobID]
	if !exist {
		return errors.NotFoundf("jobID %d", jobID)
	}
	for _, entityID := range entityIDs {
		c.cron.Remove(entityID)
	}
	delete(c.jobs, jobID)
	return nil
}
