package data_pipeline

import (
	"context"

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

type FilterOp func(entity.DataPipelineQuerySet) entity.DataPipelineQuerySet

type DataPipelineRepo interface {
	AllocateID() entity.ID
	Create(ctx context.Context, pipeline *entity.DataPipeline) bizerr.BizError
	Load(ctx context.Context, id uint64) (*entity.DataPipeline, bizerr.BizError)
	Get(ctx context.Context, ops ...FilterOp) (*entity.DataPipeline, bizerr.BizError)
	List(ctx context.Context, ops ...FilterOp) ([]entity.DataPipeline, bizerr.BizError)
	Count(ctx context.Context, ops ...FilterOp) (int64, bizerr.BizError)
	Save(ctx context.Context, pipeline *entity.DataPipeline) bizerr.BizError
	Delete(ctx context.Context, id uint64) bizerr.BizError
}

func WithTenantID(tenantID uint64) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.TenantIDEq(entity.ID(tenantID))
	}
}

func WithClusterID(clusterID uint64) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.ClusterIDEq(entity.ID(clusterID))
	}
}

func WithIDs(ids ...uint64) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		if len(ids) == 0 {
			// An empty filter must not widen the query to the whole table.
			return qs.IDEq(0)
		}
		entityIDs := make([]entity.ID, 0, len(ids))
		for _, id := range ids {
			entityIDs = append(entityIDs, entity.ID(id))
		}
		return qs.IDIn(entityIDs...)
	}
}

func WithIDAfter(id uint64) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.IDGt(entity.ID(id))
	}
}

func WithStatuses(statuses ...entity.DataPipelineStatus) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		if len(statuses) == 0 {
			return qs.StatusEq("")
		}
		return qs.StatusIn(statuses...)
	}
}

func WithPagination(offset, limit int) FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.Offset(offset).Limit(limit)
	}
}

func OrderByIDAsc() FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.OrderAscByID()
	}
}

func OrderByIDDesc() FilterOp {
	return func(qs entity.DataPipelineQuerySet) entity.DataPipelineQuerySet {
		return qs.OrderDescByID()
	}
}
