using AutoMapper;
using Bit.Core.Entities;
using Bit.Infrastructure.EntityFramework.Repositories;
using Bit.Seeder.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
namespace Bit.Seeder.Pipeline;
///
/// Orchestrates preset-based seeding by coordinating the Pipeline infrastructure.
///
internal sealed class PresetExecutor(DatabaseContext db, IMapper mapper)
{
///
/// Executes a preset by registering its recipe, building a service provider, and running all steps.
///
/// Name of the embedded preset (e.g., "dunder-mifflin-full")
/// Password hasher for user creation
/// Mangler service for test isolation
/// Optional password for all seeded accounts
/// Execution result with organization ID and entity counts
internal ExecutionResult Execute(
string presetName,
IPasswordHasher passwordHasher,
IManglerService manglerService,
string? password = null)
{
var reader = new SeedReader();
var services = new ServiceCollection();
services.AddSingleton(passwordHasher);
services.AddSingleton(manglerService);
services.AddSingleton(reader);
services.AddSingleton(new SeederSettings(password));
services.AddSingleton(db);
PresetLoader.RegisterRecipe(presetName, reader, services);
using var serviceProvider = services.BuildServiceProvider();
var committer = new BulkCommitter(db, mapper);
var executor = new RecipeExecutor(presetName, serviceProvider, committer);
return executor.Execute();
}
///
/// Lists all available embedded presets and fixtures.
///
/// Available presets grouped by category
internal static AvailableSeeds ListAvailable()
{
var seedReader = new SeedReader();
var all = seedReader.ListAvailable();
var presets = all.Where(n => n.StartsWith("presets."))
.Select(n => n["presets.".Length..])
.ToList();
var fixtures = all.Where(n => !n.StartsWith("presets."))
.GroupBy(n => n.Split('.')[0])
.ToDictionary(
g => g.Key,
g => (IReadOnlyList)g.ToList());
return new AvailableSeeds(presets, fixtures);
}
}
///
/// Result of pipeline execution with organization ID and entity counts.
///
internal record ExecutionResult(
Guid OrganizationId,
string? OwnerEmail,
int UsersCount,
int GroupsCount,
int CollectionsCount,
int CiphersCount);
///
/// Available presets and fixtures grouped by category.
///
internal record AvailableSeeds(
IReadOnlyList Presets,
IReadOnlyDictionary> Fixtures);