using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using NeonSprawl.Server.Game.Items;
using NeonSprawl.Server.Game.Skills;

namespace NeonSprawl.Server.Game.Crafting;

/// <summary>DI registration for the fail-fast recipe catalog (NEO-66) and recipe definition registry (NEO-67).</summary>
public static class RecipeCatalogServiceCollectionExtensions
{
    /// <summary>Binds <see cref="ContentPathsOptions"/> and registers <see cref="RecipeDefinitionCatalog"/> and <see cref="IRecipeDefinitionRegistry"/> as singletons.</summary>
    public static IServiceCollection AddRecipeDefinitionCatalog(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddOptions<ContentPathsOptions>()
            .Bind(configuration.GetSection(ContentPathsOptions.SectionName));

        services.AddSingleton<RecipeDefinitionCatalog>(sp =>
        {
            var hostEnv = sp.GetRequiredService<IHostEnvironment>();
            var opts = sp.GetRequiredService<IOptions<ContentPathsOptions>>().Value;
            var itemCatalog = sp.GetRequiredService<ItemDefinitionCatalog>();
            var skillCatalog = sp.GetRequiredService<SkillDefinitionCatalog>();
            var logger = sp.GetRequiredService<ILoggerFactory>()
                .CreateLogger("NeonSprawl.Server.Game.Crafting.RecipeCatalog");

            var recipesDir = RecipeCatalogPathResolution.ResolveRecipesDirectory(
                opts.RecipesDirectory,
                hostEnv.ContentRootPath);
            var recipeDefSchemaPath = RecipeCatalogPathResolution.ResolveRecipeDefSchemaPath(
                recipesDir,
                opts.RecipeDefSchemaPath,
                hostEnv.ContentRootPath);
            var recipeIoRowSchemaPath = RecipeCatalogPathResolution.ResolveRecipeIoRowSchemaPath(
                recipesDir,
                opts.RecipeIoRowSchemaPath,
                hostEnv.ContentRootPath);

            var knownItemIds = itemCatalog.ById.Keys.ToHashSet(StringComparer.Ordinal);
            var knownSkillIds = skillCatalog.ById.Keys.ToHashSet(StringComparer.Ordinal);

            return RecipeDefinitionCatalogLoader.Load(
                recipesDir,
                recipeDefSchemaPath,
                recipeIoRowSchemaPath,
                knownItemIds,
                knownSkillIds,
                logger);
        });

        services.AddSingleton<IRecipeDefinitionRegistry>(sp =>
            new RecipeDefinitionRegistry(sp.GetRequiredService<RecipeDefinitionCatalog>()));

        return services;
    }
}
