package restore

import (
	"context"

	"github.com/tidbcloud/dataflow-service/app/repo/entity"
	"github.com/tidbcloud/pkgv2/bizerr"
	"github.com/tidbcloud/pkgv2/db"
)

type restoreRepoImpl struct {
	dbProvider db.Provider
}

func NewRestoreRepo(provider db.Provider) RestoreRepo {
	return &restoreRepoImpl{
		dbProvider: provider,
	}
}

func (r *restoreRepoImpl) Load(ctx context.Context, id uint64) (*entity.Restore, bizerr.BizError) {
	rdb := r.dbProvider.ReadDB(ctx)

	restore := &entity.Restore{}

	err := entity.NewRestoreQuerySet(rdb).
		PreloadBackup().
		IDEq(entity.ID(id)).
		One(restore)
	if err != nil {
		return nil, bizerr.WrapGormError(err, "restore %d is not found", id)
	}

	return restore, nil
}

func (r *restoreRepoImpl) Save(ctx context.Context, restore *entity.Restore) bizerr.BizError {
	wdb := r.dbProvider.WriteDB(ctx)

	if err := entity.SaveWithVersioning(wdb, restore); err != nil {
		return err.Chain("save restore, id=%d", restore.ID)
	}

	return nil
}

func (r *restoreRepoImpl) Count(ctx context.Context, ops ...RestoreFilterOp) (int64, bizerr.BizError) {
	rdb := r.dbProvider.ReadDB(ctx)

	qs := entity.NewRestoreQuerySet(rdb)
	for _, op := range ops {
		qs = op(qs)
	}

	count, err := qs.Offset(-1).Limit(-1).Count()
	if err != nil {
		return 0, bizerr.WrapGormError(err, "count restore occur error")
	}

	return count, nil
}

func (r *restoreRepoImpl) List(
	ctx context.Context,
	ops ...RestoreFilterOp,
) ([]entity.Restore, bizerr.BizError) {
	rdb := r.dbProvider.ReadDB(ctx)

	qs := entity.NewRestoreQuerySet(rdb)
	for _, op := range ops {
		qs = op(qs)
	}

	var restores []entity.Restore
	if err := qs.All(&restores); err != nil {
		return nil, bizerr.WrapGormError(err, "list restores occur error, ops is %v", ops)
	}

	return restores, nil
}

// Get return only one data
func (r *restoreRepoImpl) Get(
	ctx context.Context,
	ops ...RestoreFilterOp,
) (*entity.Restore, bizerr.BizError) {
	rdb := r.dbProvider.ReadDB(ctx)

	qs := entity.NewRestoreQuerySet(rdb)
	for _, op := range ops {
		qs = op(qs)
	}

	restore := &entity.Restore{}
	if err := qs.One(restore); err != nil {
		return nil, bizerr.WrapGormError(err, "get restore occur error, ops is %v", ops)
	}

	return restore, nil
}
