package scheduled

import (
	"time"

	"github.com/doug-martin/goqu/v9"
	"github.com/doug-martin/goqu/v9/exp"

	"github.com/pingcap/test-infra/common/model"
	"github.com/pingcap/test-infra/services/tcms/utils"
	"github.com/pingcap/test-infra/services/tcms/utils/sql"
)

func NewDailyRunThrottle(db *sql.Database) *dailyRunThrottle {
	return &dailyRunThrottle{db: db}
}

const CancelledNote = "CANCELED BY FLOW RATE LIMITING"

type dailyRunThrottle struct {
	db *sql.Database
}

func (t *dailyRunThrottle) Run() {
	var (
		timeStart = time.Now().Add(-24 * time.Hour)
	)

	t.cancelRedundantExecs(&timeStart)
}

func (t *dailyRunThrottle) cancelRedundantExecs(timeStart *time.Time) {
	ctx := utils.FakeCtx()

	subqueryTrigger := sql.Builder.
		Select("*").
		From("triggers").
		Where(goqu.L("trigger_id=triggers.id AND triggers.type='" + string(model.TriggerTypeCron) + "'"))
	subqueryOldCronTriggers := sql.Builder.
		Select("trigger_id").
		Distinct().
		From("plan_executions").
		Where(goqu.Func("EXISTS", subqueryTrigger),
			goqu.C("created_at").Lt(timeStart),
			goqu.C("status").In([]model.ExecutionStatus{model.ExecutionStatusRunning, model.ExecutionStatusPending}),
		)

	where := []exp.Expression{}
	where = append(where, goqu.C("status").In([]model.ExecutionStatus{model.ExecutionStatusRunning, model.ExecutionStatusPending}))
	where = append(where, goqu.C("created_at").Gte(timeStart))
	where = append(where, goqu.C("trigger_id").In(sql.Builder.Select("trigger_id").From(subqueryOldCronTriggers)))

	query, args, _ := sql.Builder.Update("plan_executions").Prepared(true).Set(
		map[string]interface{}{"status": string(model.ExecutionStatusCancelling), "note": CancelledNote},
	).Where(where...).ToSQL()

	if _, err := t.db.ExecContext(ctx.Request().Context(), query, args...); err != nil {
		ctx.Log().Errorf(err, "cancel duplicated cron executions failed")
	}
}
