package ratecontroller

import (
	"context"
	"time"

	"github.com/pingcap/errors"
	"github.com/tidbcloud/metrics-server/central/db"
	"github.com/tidbcloud/metrics-server/central/db/entity"
	"github.com/tidbcloud/metrics-server/pkg/ratecontroller/types"
	"gorm.io/gorm"
)

type tidbStore struct {
}

func NewTidbStore() *tidbStore {
	return &tidbStore{}
}

func (r *tidbStore) AddEntry(ctx context.Context, scene *types.Scene, accessor, target string, ts time.Time) error {
	entry := &entity.AccessLog{
		Accessor:  accessor,
		Scene:     scene.SceneKey,
		Timestamp: ts,
		Target:    target,
	}
	err := db.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(entry).Error; err != nil {
			return errors.Annotate(err, "create access log failed")
		}
		return nil
	})

	return err
}

func (r *tidbStore) PurgeExpired(ctx context.Context, scene *types.Scene, accessor string, expiredFrom time.Time) error {
	err := db.Transaction(func(tx *gorm.DB) error {
		err := tx.Where("scene=? AND accessor=? AND timestamp<?", scene.SceneKey, accessor, expiredFrom).
			Delete(&entity.AccessLog{}).Error
		return errors.Annotate(err, "purge expired access log failed")
	})

	return err
}

func (r *tidbStore) PurgeOverflowed(ctx context.Context, scene *types.Scene, accessor string) error {
	// do nothing
	return nil
}

func (r *tidbStore) Count(ctx context.Context, scene *types.Scene, accessor, target string, startTime, endTime time.Time) (int64, error) {
	var cnt int64
	err := db.Transaction(func(tx *gorm.DB) error {
		tx = tx.Model(&entity.AccessLog{}).Where("scene=? AND accessor=? AND timestamp BETWEEN ? AND ?",
			scene.SceneKey, accessor, startTime, endTime)
		if target != "" {
			tx = tx.Where("target=?", target)
		}
		err := tx.Count(&cnt).Error
		return errors.Annotate(err, "count access log failed")
	})

	return cnt, err
}
