package repository

import (
	"context"

	"github.com/tech/sendico/pkg/db/internal/mongo/repositoryimp"
	"github.com/tech/sendico/pkg/db/repository/builder"
	rd "github.com/tech/sendico/pkg/db/repository/decoder"
	ri "github.com/tech/sendico/pkg/db/repository/index"
	"github.com/tech/sendico/pkg/db/storable"
	"github.com/tech/sendico/pkg/model"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"
)

type (
	// FilterQuery selects documents to operate on.
	FilterQuery = builder.Query
	// PatchDoc defines field/value modifications for partial updates.
	PatchDoc = builder.Patch
)

type Repository interface {
	Aggregate(ctx context.Context, builder builder.Pipeline, decoder rd.DecodingFunc) error
	Insert(ctx context.Context, obj storable.Storable, getFilter builder.Query) error
	InsertMany(ctx context.Context, objects []storable.Storable) error
	Get(ctx context.Context, id bson.ObjectID, result storable.Storable) error
	FindOneByFilter(ctx context.Context, builder builder.Query, result storable.Storable) error
	FindManyByFilter(ctx context.Context, builder builder.Query, decoder rd.DecodingFunc) error
	Update(ctx context.Context, obj storable.Storable) error
	// Upsert replaces the document identified by obj ID, inserting it when no document exists.
	Upsert(ctx context.Context, obj storable.Storable) error
	// Patch applies partial updates defined by patch to the document identified by id.
	Patch(ctx context.Context, id bson.ObjectID, patch PatchDoc) error
	// PatchMany applies partial updates defined by patch to all documents matching filter and returns the number of updated documents.
	PatchMany(ctx context.Context, filter FilterQuery, patch PatchDoc) (int, error)
	Delete(ctx context.Context, id bson.ObjectID) error
	DeleteMany(ctx context.Context, query builder.Query) error
	CreateIndex(def *ri.Definition) error
	ListIDs(ctx context.Context, query builder.Query) ([]bson.ObjectID, error)
	ListPermissionBound(ctx context.Context, query builder.Query) ([]model.PermissionBoundStorable, error)
	ListAccountBound(ctx context.Context, query builder.Query) ([]model.AccountBoundStorable, error)
	Collection() string
}

func CreateMongoRepository(db *mongo.Database, collection string) Repository {
	return repositoryimp.NewMongoRepository(db, collection)
}
