package schedulers

import (
	"context"
	"time"

	"github.com/pingcap/test-infra/services/tps/pkg/common"
	"github.com/pingcap/test-infra/services/tps/pkg/schedulers/resource"
)

// Scheduler will choose plans to execute

type BaseScheduler interface {
	Name() string
}

type RefreshScheduler interface {
	BaseScheduler
	Refresh(ctx context.Context) error
}

type PrefilterScheduler interface {
	BaseScheduler
	// Prefilter is used to pre-process job info
	// It can modify job
	// The job will be set error if it returns error
	Prefilter(ctx context.Context, job *common.ArgoJob) error
}

type FilterScheduler interface {
	BaseScheduler
	// Filter is to choose jobs that can run
	// It should not modify job
	Filter(ctx context.Context, jobs []*common.ArgoJob) ([]*common.ArgoJob, error)
}

type ReserveScheduler interface {
	BaseScheduler
	// Reserve will be invoked after filter, it is useful to reserve resources
	// It should not modify job
	// The job will be set error if it returns error
	Reserve(ctx context.Context, job common.ArgoJob) error
}

type CompleteScheduler interface {
	BaseScheduler
	RefreshScheduler
	PrefilterScheduler
	FilterScheduler
	ReserveScheduler
}

func InitDefaultScheduler() {
	sorter := &Sorter{}
	priority := &PriorityScheduler{now: time.Now}
	resourceScheduler := resource.NewResourcePoolScheduler()
	leaky := &LeakyScheduler{}
	backoff := &Backoff{now: time.Now}
	pto := &WaitTimeout{now: time.Now}

	DefaultScheduler = &ChainScheduler{
		refreshSchedulers:   []RefreshScheduler{resourceScheduler},
		prefilterSchedulers: []PrefilterScheduler{pto, priority, resourceScheduler},
		filterSchedulers:    []FilterScheduler{priority, backoff, sorter, resourceScheduler, leaky},
		reserveSchedulers:   []ReserveScheduler{resourceScheduler},
	}
}

var DefaultScheduler CompleteScheduler
