package schedule

import (
	"context"
	"time"

	log "github.com/sirupsen/logrus"
	"github.com/tidbcloud/observability/o11ymetering/pkg/facade"
)

type Task struct {
	Name          string
	start         int64
	interval      time.Duration
	immediately   bool
	nextTimestamp func(ctx context.Context, checkpoint int64, start int64) int64
	ready         func(ctx context.Context, timestamp int64) bool
	execute       func(ctx context.Context, timestamp int64) error
	uploadData    bool
}

func (t Task) AsyncTicker() {
	go func() {
		ticker := time.NewTicker(t.interval)
		if t.immediately {
			t.Execute()
		}
		for range ticker.C {
			t.Execute()
		}
	}()
}

func (t Task) Execute() {
	ctx := context.TODO()
	checkpoint, err := facade.GetCheckpointReaderWriter().GetCheckpoint(ctx, t.Name)
	if err != nil {
		panic(err)
	}
	next := t.nextTimestamp(ctx, checkpoint, t.start)

	if !t.ready(ctx, next) {
		log.Infof("not time to execute task, name = %s, timestamp = %d,", t.Name, next)
		return
	}

	log.Infof("start to execute next task, name = %s, timestamp = %d,", t.Name, next)
	err = t.execute(ctx, next)
	if err != nil {
		panic(err)
	}
	log.Infof("execute task succeed, start to upload data, name = %s, timestamp = %d,", t.Name, next)

	if t.uploadData {
		err = facade.GetScheduleTaskDataSync().Upload(ctx, t.Name, next)
		if err != nil {
			panic(err)
		}
		log.Infof("upload data succeed, start to save checkpoint, name = %s, timestamp = %d,", t.Name, next)
	}

	err = facade.GetCheckpointReaderWriter().SaveCheckpoint(ctx, t.Name, next)
	if err != nil {
		panic(err)
	}
}
