package store

import (
	"context"

	"github.com/tech/sendico/pkg/db/repository"
	"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"
)

// repositoryStub provides a stub implementation of repository.Repository for testing
type repositoryStub struct {
	AggregateFunc        func(ctx context.Context, pipeline builder.Pipeline, decoder rd.DecodingFunc) error
	GetFunc              func(ctx context.Context, id bson.ObjectID, result storable.Storable) error
	InsertFunc           func(ctx context.Context, object storable.Storable, filter builder.Query) error
	InsertManyFunc       func(ctx context.Context, objects []storable.Storable) error
	UpdateFunc           func(ctx context.Context, object storable.Storable) error
	UpsertFunc           func(ctx context.Context, object storable.Storable) error
	DeleteFunc           func(ctx context.Context, id bson.ObjectID) error
	FindOneByFilterFunc  func(ctx context.Context, filter builder.Query, result storable.Storable) error
	FindManyByFilterFunc func(ctx context.Context, filter builder.Query, decoder rd.DecodingFunc) error
	PatchFunc            func(ctx context.Context, id bson.ObjectID, patch repository.PatchDoc) error
	PatchManyFunc        func(ctx context.Context, filter repository.FilterQuery, patch repository.PatchDoc) (int, error)
	DeleteManyFunc       func(ctx context.Context, query builder.Query) error
	ListIDsFunc          func(ctx context.Context, query builder.Query) ([]bson.ObjectID, error)
	CreateIndexFunc      func(def *ri.Definition) error
}

func (r *repositoryStub) Aggregate(ctx context.Context, pipeline builder.Pipeline, decoder rd.DecodingFunc) error {
	if r.AggregateFunc != nil {
		return r.AggregateFunc(ctx, pipeline, decoder)
	}
	return nil
}

func (r *repositoryStub) Get(ctx context.Context, id bson.ObjectID, result storable.Storable) error {
	if r.GetFunc != nil {
		return r.GetFunc(ctx, id, result)
	}
	return nil
}

func (r *repositoryStub) Insert(ctx context.Context, object storable.Storable, filter builder.Query) error {
	if r.InsertFunc != nil {
		return r.InsertFunc(ctx, object, filter)
	}
	return nil
}

func (r *repositoryStub) InsertMany(ctx context.Context, objects []storable.Storable) error {
	if r.InsertManyFunc != nil {
		return r.InsertManyFunc(ctx, objects)
	}
	return nil
}

func (r *repositoryStub) Update(ctx context.Context, object storable.Storable) error {
	if r.UpdateFunc != nil {
		return r.UpdateFunc(ctx, object)
	}
	return nil
}

func (r *repositoryStub) Upsert(ctx context.Context, object storable.Storable) error {
	if r.UpsertFunc != nil {
		return r.UpsertFunc(ctx, object)
	}
	return nil
}

func (r *repositoryStub) Delete(ctx context.Context, id bson.ObjectID) error {
	if r.DeleteFunc != nil {
		return r.DeleteFunc(ctx, id)
	}
	return nil
}

func (r *repositoryStub) FindOneByFilter(ctx context.Context, filter builder.Query, result storable.Storable) error {
	if r.FindOneByFilterFunc != nil {
		return r.FindOneByFilterFunc(ctx, filter, result)
	}
	return nil
}

func (r *repositoryStub) FindManyByFilter(ctx context.Context, filter builder.Query, decoder rd.DecodingFunc) error {
	if r.FindManyByFilterFunc != nil {
		return r.FindManyByFilterFunc(ctx, filter, decoder)
	}
	return nil
}

func (r *repositoryStub) Patch(ctx context.Context, id bson.ObjectID, patch repository.PatchDoc) error {
	if r.PatchFunc != nil {
		return r.PatchFunc(ctx, id, patch)
	}
	return nil
}

func (r *repositoryStub) PatchMany(ctx context.Context, filter repository.FilterQuery, patch repository.PatchDoc) (int, error) {
	if r.PatchManyFunc != nil {
		return r.PatchManyFunc(ctx, filter, patch)
	}
	return 0, nil
}

func (r *repositoryStub) DeleteMany(ctx context.Context, query builder.Query) error {
	if r.DeleteManyFunc != nil {
		return r.DeleteManyFunc(ctx, query)
	}
	return nil
}

func (r *repositoryStub) ListIDs(ctx context.Context, query builder.Query) ([]bson.ObjectID, error) {
	if r.ListIDsFunc != nil {
		return r.ListIDsFunc(ctx, query)
	}
	return []bson.ObjectID{}, nil
}

func (r *repositoryStub) ListPermissionBound(ctx context.Context, query builder.Query) ([]model.PermissionBoundStorable, error) {
	return []model.PermissionBoundStorable{}, nil
}

func (r *repositoryStub) ListAccountBound(ctx context.Context, query builder.Query) ([]model.AccountBoundStorable, error) {
	return []model.AccountBoundStorable{}, nil
}

func (r *repositoryStub) Collection() string {
	return "test_collection"
}

func (r *repositoryStub) CreateIndex(def *ri.Definition) error {
	if r.CreateIndexFunc != nil {
		return r.CreateIndexFunc(def)
	}
	return nil
}

// Note: For unit tests with FindManyByFilter, we don't simulate the full cursor iteration
// since we can't easily mock *mongo.Cursor. These tests verify that the store calls the
// repository correctly. Integration tests with real MongoDB test the actual iteration logic.
