package service

import (
	"context"
	"os"

	"go.uber.org/dig"

	"github.com/tidbcloud/pov-service/internal/common/params"
	"github.com/tidbcloud/pov-service/internal/model"
	"github.com/tidbcloud/pov-service/pkg/browser"
)

type Workload interface {
	ListWorkloads(context.Context, params.ListWorkloads) ([]model.Workload, error)
	GetWorkloadUsage(context.Context) (map[int64]int, error)
	GetWorkload(ctx context.Context, id int64) (model.Workload, error)
	GetWorkloadTest(context.Context, string) (model.WorkloadTest, error)

	ListWorkloadTests(context.Context, params.ListWorkloadTests) ([]model.WorkloadTest, error)

	// @RunWorkloadTest: Trigger workload automatically once created
	RunWorkloadTest(context.Context, params.RunWorkload, string) (model.WorkloadTest, error)

	StopWorkloadTest(context.Context, string) (model.WorkloadTest, error)

	ScaleCluster(context.Context, string, int) error

	UpdateClusterRU(context.Context, string, int64, int64) error

	InjectFailure(context.Context, string, string) error

	RollbackFailure(context.Context, string) error

	UpdateTrafficMaxConn(
		ctx context.Context,
		testID string,
		maxConNumber int,
	) error

	UpdateWorkloadTest(
		ctx context.Context,
		testID string,
		params params.UpdateWorkloadTest,
	) error
	InstructWorkloadTest(
		ctx context.Context,
		testID string,
		params params.InstructWorkloadTest,
	) error

	SampleDBs(
		ctx context.Context,
		testID string,
		options model.SampleDBOptions) (model.DBSampleResult, error)

	SampleData(
		ctx context.Context,
		testID string,
		options model.SampleDataOptions) (model.TableQueryResult, error)

	ListAuditLog(
		ctx context.Context,
		testID string,
	) ([]model.AuditLog, error)

	TriggerPrepareData(
		ctx context.Context,
		testID string) (model.WorkloadTest, error)

	TriggerRunTraffic(
		ctx context.Context,
		testID string) (model.WorkloadTest, error)

	TriggerCreateCluster(
		ctx context.Context,
		testID string) (model.WorkloadTest, error)

	PreserveWorkloadSample(
		ctx context.Context,
		workloadID int64,
		cluster model.TiDBCluster,
	) error

	GetPreservedSampleDBs(
		ctx context.Context,
		workloadID int64) (model.DBSampleResult, error)

	GetPreservedSampleData(
		ctx context.Context,
		workloadID int64,
		dbName, tableName string,
	) (model.TableQueryResult, error)

	DownloadTestPDF(
		ctx context.Context,
		testID string,
		opts browser.PrintPDFOptions,
	) (*os.File, error)
}

type Script interface {
	ListTemplates(ctx context.Context) ([]model.ScriptTemplate, error)
	List(
		ctx context.Context,
		params params.ListScripts,
	) ([]model.Script, error)
	Activate(ctx context.Context, testID string, scrptID int64) (model.ScriptExec, error)
	CreateTemplate(ctx context.Context, tmpl model.ScriptTemplate) (model.ScriptTemplate, error)
	UpdateTemplate(ctx context.Context, tmpl model.ScriptTemplate) (model.ScriptTemplate, error)
	DeleteTemplate(ctx context.Context, id int64) error
	Create(ctx context.Context, script model.Script) (model.Script, error)
	Update(ctx context.Context, script model.Script) (model.Script, error)
	Delete(ctx context.Context, id int64) error
}

type Runner interface {
	Run(ctx context.Context) error
}

// INFO: add isolated audit log service if needed, for example: we would like to record audit log from eventbus...

type ManagerParams struct {
	dig.In

	Runnables []Runnable `group:"runnable"`
}

type Runnable interface {
	Run(ctx context.Context) error
}

type Manager struct {
	Runnables []Runnable
}

func NewManager(param ManagerParams) *Manager {
	return &Manager{
		Runnables: param.Runnables,
	}
}

func (m *Manager) Run(ctx context.Context) error {
	for _, svc := range m.Runnables {
		if err := svc.Run(ctx); err != nil {
			return err
		}
	}
	return nil
}
