package trigger

import (
	"context"
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/pkg/storage"
	"github.com/pingcap/schrodinger/pkg/types"
)

// Job is a job
type Job struct {
	ID    int64
	Fn    func()
	Rules types.Rules
}

// Trigger is trigger client
type Trigger struct {
	ctx context.Context

	storage *storage.Storage

	cron        Interface
	immediately Interface
	github      Interface
}

// New creates trigger
func New(ctx context.Context, s *storage.Storage) *Trigger {
	return &Trigger{
		ctx:         ctx,
		cron:        NewCronTrigger(ctx),
		immediately: NewImmediatelyTrigger(s),
		github:      NewGithubTrigger(ctx, s),
		storage:     s,
	}
}

// AddJob adds job
func (t *Trigger) AddJob(job *Job) error {
	for _, rule := range job.Rules {
		err := t.addRule(rule, job.Fn, job.ID)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

// DelJob deletes job
func (t *Trigger) DelJob(jobID int64) error {
	err := t.cron.DelJob(jobID)
	if err != nil && !strings.Contains(err.Error(), "not found") {
		return errors.Trace(err)
	}
	err = t.github.DelJob(jobID)
	if err != nil && !strings.Contains(err.Error(), "not found") {
		return errors.Trace(err)
	}
	return nil
}

func (t *Trigger) addRule(rule types.Rule, fn func(), jobID int64) error {
	switch rule.Type {
	case types.JobCron:
		return errors.Trace(t.cron.AddJob(rule.Value, fn, jobID))
	case types.JobImmediately:
		return errors.Trace(t.immediately.AddJob(rule.Value, fn, jobID))
	case types.JobGitWebhook:
		return errors.Trace(t.github.AddJob(rule.Value, fn, jobID))
	}
	return errors.NotFoundf("rule type %s", rule.Type)
}
