package mo

import "context"

// Shortcut 是操作 Collection 的快捷方式, 没有自定义功能
type Shortcut struct {
	coll *Collection
}

func NewShortcut(coll *Collection) *Shortcut {
	return &Shortcut{coll: coll}
}

// Aggregate 管道聚合
func (s *Shortcut) Aggregate(pipeline any, opts ...*AggregateOptions) (*Cursor, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if pipeline == nil {
		pipeline = Pipeline{}
	}
	return s.coll.Aggregate(ctx, pipeline, opts...)
}

// Find 查找文档, 使用 filter 作为条件
func (s *Shortcut) Find(filter any, opts ...*FindOptions) (*Cursor, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.Find(ctx, filter, opts...)
}

// FindOne 查找一条文档. 错误详情见 SingleResult
func (s *Shortcut) FindOne(filter any, opts ...*FindOneOptions) *SingleResult {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.FindOne(ctx, filter, opts...)
}

// FindOneAndDelete 查找一条文档, 然后删除. 错误详情见 SingleResult
func (s *Shortcut) FindOneAndDelete(filter any, opts ...*FindOneAndDeleteOptions) *SingleResult {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.FindOneAndDelete(ctx, filter, opts...)
}

// FindOneAndUpdate 查找一条文档, 然后使用 update 更新. 错误详情见 SingleResult
// Update 操作符 https://www.mongodb.com/docs/manual/reference/operator/update-field/
func (s *Shortcut) FindOneAndUpdate(filter, update any, opts ...*FindOneAndUpdateOptions) *SingleResult {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.FindOneAndUpdate(ctx, filter, update, opts...)
}

// FindOneAndReplace TODO
func (s *Shortcut) FindOneAndReplace() {}

// CountDocuments 合集文档数量, 使用 filter 作为条件. 当不需要查询条件时推荐使用 EstimatedDocumentCount
func (s *Shortcut) CountDocuments(filter any, opts ...*CountOptions) (int64, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.CountDocuments(ctx, filter, opts...)
}

// EstimatedDocumentCount 返回合集内文档的数量. 此方法无法添加过滤条件, 当需要过滤条件时使用 CountDocuments
func (s *Shortcut) EstimatedDocumentCount(opts ...*EstimatedDocumentCountOptions) (int64, error) {
	ctx, cancel := getCtx()
	defer cancel()
	return s.coll.EstimatedDocumentCount(ctx, opts...)
}

// Indexes 索引操作
func (s *Shortcut) Indexes() IndexView {
	return s.coll.Indexes()
}

// InsertOne 插入一条文档
func (s *Shortcut) InsertOne(doc any, opts ...*InsertOneOptions) (*InsertOneResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	return s.coll.InsertOne(ctx, doc, opts...)
}

// InsertMany 插入多条文档
func (s *Shortcut) InsertMany(doc []any, opts ...*InsertManyOptions) (*InsertManyResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	return s.coll.InsertMany(ctx, doc, opts...)
}

// DeleteOne 删除一条文档, 使用 filter 作为条件
func (s *Shortcut) DeleteOne(filter any, opts ...*DeleteOptions) (*DeleteResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.DeleteOne(ctx, filter, opts...)
}

// DeleteMany 删除多条文档, 使用 filter 作为条件
func (s *Shortcut) DeleteMany(filter any, opts ...*DeleteOptions) (*DeleteResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.DeleteMany(ctx, filter, opts...)
}

// UpdateOne 更新一条文档, 使用 filter 作为条件
func (s *Shortcut) UpdateOne(filter, update any, opts ...*UpdateOptions) (*UpdateResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.UpdateOne(ctx, filter, update, opts...)
}

// UpdateMany 更新多条文档, 使用 filter 作为条件
func (s *Shortcut) UpdateMany(filter, update any, opts ...*UpdateOptions) (*UpdateResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	if filter == nil {
		filter = D{}
	}
	return s.coll.UpdateMany(ctx, filter, update, opts...)
}

// UpdateByID 更新一条文档, 使用 ObjectID 作为条件
func (s *Shortcut) UpdateByID(id, update any, opts ...*UpdateOptions) (*UpdateResult, error) {
	ctx, cancel := getCtx()
	defer cancel()
	return s.coll.UpdateByID(ctx, id, update, opts...)
}

// Drop 删除合集
func (s *Shortcut) Drop() error {
	ctx, cancel := getCtx()
	defer cancel()
	return s.coll.Drop(ctx)
}

func getCtx() (context.Context, context.CancelFunc) {
	return context.WithTimeout(context.Background(), DefaultTimout)
}
