using System.Text;
using NodePipeline.Engine.CodeGeneration.Abstractions;

namespace NodePipeline.Engine.DependencyInjection.CodeGeneration;

internal static class DiExtensionsGenerator
{
    public static string Generate(NodeModelBuilder.NodesModel model)
    {
        var sb = new StringBuilder();
        sb.AppendLine("using System.Globalization;");
        sb.AppendLine("using Microsoft.Extensions.DependencyInjection;");
        sb.AppendLine("using NodePipeline.Abstractions;");
        sb.AppendLine("using NodePipeline.Abstractions.Interfaces;");
        sb.AppendLine("using NodePipeline.Abstractions.Interfaces.Nodes;");
        sb.AppendLine("using NodePipeline.Abstractions.Interfaces.Validation;");
        sb.AppendLine("using NodePipeline.Engine.Abstractions;");
        sb.AppendLine("using NodePipeline.Engine.Execution;");
        sb.AppendLine("using NodePipeline.Engine.Generated;");
        sb.AppendLine();
        sb.AppendLine("#nullable enable");
        sb.AppendLine();
        sb.AppendLine("namespace NodePipeline.Engine.DependencyInjection;");
        sb.AppendLine();
        sb.AppendLine("public static class PipelineServiceCollectionExtensions");
        sb.AppendLine("{");

        sb.AppendLine(BuildAddPipelineMethod());
        sb.AppendLine();
        sb.AppendLine(BuildAddNodeFactoryMethod());
        sb.AppendLine();
        sb.AppendLine(BuildAddNodeValidatorMethod());
        sb.AppendLine();


        sb.AppendLine("}");
        sb.AppendLine();
        sb.AppendLine(BuildPipelineProviderExtensionsClass());
        sb.AppendLine();
        sb.AppendLine(BuildPipelineNodeExtensionsClass());
        sb.AppendLine();
        sb.AppendLine(BuildPipelineNodeValidatorExtensionsClass());
        sb.AppendLine();
        sb.AppendLine(BuildPipelineFieldValidatorExtensionsClass());
        sb.AppendLine("#nullable restore");
        return sb.ToString();
    }

    private static string BuildAddPipelineMethod()
    {
        var sb = new StringBuilder();
        sb.AppendLine("    public static IServiceCollection AddPipeline(this IServiceCollection services)");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddSingleton<IPipelineLocalizationProvider, PipelineLocalizationProvider>();");
        sb.AppendLine();
        sb.AppendLine("        AddNodeFactory(services);");
        sb.AppendLine("        AddNodeValidator(services);");
        sb.AppendLine();
        sb.AppendLine("        services.AddSingleton(sp => new PipelineRegistry(CultureInfo.CurrentCulture));");
        sb.AppendLine("        return services;");
        sb.AppendLine("    }");
        return sb.ToString();
    }

    private static string BuildAddNodeFactoryMethod()
    {
        var sb = new StringBuilder();
        sb.AppendLine("    private static void AddNodeFactory(IServiceCollection services)");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddScoped<GeneratedNodeFactory>();");
        sb.AppendLine("        services.AddScoped<INodeFactory>(sp =>");
        sb.AppendLine("        {");
        sb.AppendLine("            var inner = sp.GetRequiredService<GeneratedNodeFactory>();");
        sb.AppendLine(
            "            return new DiNodeFactory(sp, inner, sp.GetService<IPipelineLocalizationProvider>());");
        sb.AppendLine("        });");
        sb.AppendLine("    }");
        return sb.ToString();
    }

    private static string BuildAddNodeValidatorMethod()
    {
        var sb = new StringBuilder();
        sb.AppendLine("    private static void AddNodeValidator(IServiceCollection services)");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddScoped<GeneratedNodeValidator>();");
        sb.AppendLine("        services.AddScoped<IPipelineNodeValidator>(sp =>");
        sb.AppendLine("        {");
        sb.AppendLine("            var inner = sp.GetRequiredService<GeneratedNodeValidator>();");
        sb.AppendLine(
            "            return new DiNodeValidator(sp, inner, sp.GetService<IPipelineLocalizationProvider>());");
        sb.AppendLine("        });");
        sb.AppendLine("    }");
        return sb.ToString();
    }


    //classes
    private static string BuildPipelineProviderExtensionsClass()
    {
        var sb = new StringBuilder();
        sb.AppendLine("public static class PipelineProviderExtensions");
        sb.AppendLine("{");
        sb.AppendLine(
            "    public static IServiceCollection AddPipelineProvider<TInterface, TImplementation>(this IServiceCollection services)");
        sb.AppendLine("        where TInterface : class");
        sb.AppendLine("        where TImplementation : class, TInterface");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddScoped<TImplementation>();");
        sb.AppendLine("        services.AddScoped<TInterface>(sp => sp.GetRequiredService<TImplementation>());");
        sb.AppendLine("        return services;");
        sb.AppendLine("    }");
        sb.AppendLine("}");
        return sb.ToString();
    }

    private static string BuildPipelineNodeExtensionsClass()
    {
        var sb = new StringBuilder();
        sb.AppendLine("public static class PipelineNodeExtensions");
        sb.AppendLine("{");
        sb.AppendLine("    public static IServiceCollection AddPipelineNode<TNode>(this IServiceCollection services)");
        sb.AppendLine("        where TNode : class, INode");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddScoped<TNode>();");
        sb.AppendLine("        return services;");
        sb.AppendLine("    }");
        sb.AppendLine("}");
        return sb.ToString();
    }

    private static string BuildPipelineNodeValidatorExtensionsClass()
    {
        var sb = new StringBuilder();
        sb.AppendLine("public static class PipelineNodeValidatorExtensions");
        sb.AppendLine("{");
        sb.AppendLine(
            "    public static IServiceCollection AddPipelineNodeValidator<TValidator>(this IServiceCollection services)");
        sb.AppendLine("        where TValidator : class, INodeValidator");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddTransient<TValidator>();");
        sb.AppendLine("        return services;");
        sb.AppendLine("    }");
        sb.AppendLine("}");
        return sb.ToString();
    }

    private static string BuildPipelineFieldValidatorExtensionsClass()
    {
        var sb = new StringBuilder();
        sb.AppendLine("public static class PipelineFieldValidatorExtensions");
        sb.AppendLine("{");
        sb.AppendLine(
            "    public static IServiceCollection AddPipelineNodeFieldValidator<TValidator>(this IServiceCollection services)");
        sb.AppendLine("        where TValidator : class, INodeFieldValidator");
        sb.AppendLine("    {");
        sb.AppendLine("        services.AddTransient<TValidator>();");
        sb.AppendLine("        return services;");
        sb.AppendLine("    }");
        sb.AppendLine("}");
        return sb.ToString();
    }
}