package workflow

import (
	"context"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/tidbcloud/fastflow/pkg/entity"
	"github.com/tidbcloud/fastflow/pkg/entity/run"
)

const (
	OrgIdKey   = "org-id"
	ProjectKey = "project-id"
	BizIdKey   = "biz-id"
)

//go:generate go run go.uber.org/mock/mockgen@latest -source=$GOFILE -package=mock_$GOPACKAGE -destination=./mock_$GOPACKAGE/mock_$GOFILE
type Workflow interface {
	SetDagInstanceLifecycleHook(hook entity.DagInstanceLifecycleHook)
	// RunDag write dag instance. If you have cluster id, use RunDagWithBizId instead.
	RegisterDag(dag *entity.Dag, actions []run.Action) error

	RunDag(ctx context.Context, dagId, orgId, projectId string, specVar map[string]string) error
	RunDagWithBizId(ctx context.Context, dagId, orgId, projectId, bizId string, specVar map[string]string) error
	RegisterDynamicDagThenRun(ctx context.Context, prefix string, opt *CreateDynamicDagOption) error

	ListRunningDagInstances(ctx context.Context, dagIds []string, bizId string) ([]*entity.DagInstance, error)
	ListRunningDagInstancesByBizIds(ctx context.Context, dagIds []string, bizIds []string) ([]*entity.DagInstance, error)
	ListRunningDagInstancesByNamePrefix(ctx context.Context, namePrefix, bizId string) ([]*entity.DagInstance, error)
	ListRunningDagInstancesByOrgId(ctx context.Context, dagIds []string, orgId string) ([]*entity.DagInstance, error)
	ListAllRunningDagInstances() ([]*entity.DagInstance, error)
	ListAllRunningTaskInstances() ([]*entity.TaskInstance, error)

	DeleteDagInstances(ctx context.Context, bizId string, excludeDags map[string]bool) error
	DeleteDagInstancesWithDagId(ctx context.Context, bizId, dagId string) error

	IsLeader() bool
	Start() error
	Close()

	// RegisterMetrics register workflow dag instance metrics to prometheus
	RegisterMetrics(registry prometheus.Registerer)
}

type ID string

type Mode string

const (
	ModeDispatcher  Mode = "dispatcher"
	ModeCompetitive Mode = "competitive"
)

type NewWorkflowOption func(*NewWorkflowConfig)

type NewWorkflowConfig struct {
	WorkerMode  Mode
	Competitive CompetitiveOption
}

type CompetitiveOption struct {
	ClaimLimit        int
	ClaimInterval     time.Duration
	LeaseStaleTTL     time.Duration
	LeaseReclaimLimit int
}

func WithWorkerMode(mode Mode) NewWorkflowOption {
	return func(cfg *NewWorkflowConfig) {
		cfg.WorkerMode = mode
	}
}

func WithCompetitiveOption(opt CompetitiveOption) NewWorkflowOption {
	return func(cfg *NewWorkflowConfig) {
		cfg.Competitive = opt
	}
}
