package billing

import (
	"context"

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

type billingRecordRepoImpl struct {
	dbProvider db.Provider
}

func NewBillingRecordRepo(dbProvider db.Provider) repo.BillingRecordRepo {
	return &billingRecordRepoImpl{dbProvider: dbProvider}
}

func (b *billingRecordRepoImpl) Load(ctx context.Context, id uint64) (*entity.BillingRecord, bizerr.BizError) {
	rdb := b.dbProvider.ReadDB(ctx)
	record := &entity.BillingRecord{}
	err := entity.NewBillingRecordQuerySet(rdb).
		IDEq(entity.ID(id)).
		One(record)
	if err != nil {
		return nil, bizerr.WrapGormError(err, "list billing record occur error")
	}
	return record, nil
}

func (b *billingRecordRepoImpl) Save(ctx context.Context, record *entity.BillingRecord) bizerr.BizError {
	wdb := b.dbProvider.WriteDB(ctx)
	if err := entity.SaveWithVersioning(wdb, record); err != nil {
		return err.Chain("save record, id=%d", record.ID)
	}
	return nil
}

func (b *billingRecordRepoImpl) List(
	ctx context.Context, ops ...repo.BillingRecordFilterOp,
) ([]entity.BillingRecord, bizerr.BizError) {
	rdb := b.dbProvider.ReadDB(ctx)

	qs := entity.NewBillingRecordQuerySet(rdb)
	for _, op := range ops {
		qs = op(qs)
	}
	var records []entity.BillingRecord
	if err := qs.All(&records); err != nil {
		return nil, bizerr.WrapGormError(err, "list billing records occur error")
	}
	return records, nil
}

func (b *billingRecordRepoImpl) Get(
	ctx context.Context, ops ...repo.BillingRecordFilterOp,
) (*entity.BillingRecord, bizerr.BizError) {
	rdb := b.dbProvider.ReadDB(ctx)

	qs := entity.NewBillingRecordQuerySet(rdb)
	for _, op := range ops {
		qs = op(qs)
	}
	record := &entity.BillingRecord{}
	if err := qs.One(record); err != nil {
		return nil, bizerr.WrapGormError(err, "get billing record occur error")
	}
	return record, nil
}

func (b *billingRecordRepoImpl) Count(ctx context.Context, ops ...repo.BillingRecordFilterOp,
) (int64, bizerr.BizError) {
	rdb := b.dbProvider.ReadDB(ctx)

	qs := entity.NewBillingRecordQuerySet(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 billing record occur error")
	}
	return count, nil
}
