namespace Adapters.Driving.Api.Extensions;

using Adapters.Driven.Persistence.DataLoaders;
using Adapters.Driving.Api.Middleware;
using Adapters.Driving.Api.Types;
using HotChocolate.Execution.Options;
using Microsoft.Extensions.DependencyInjection;

public static class GraphQLExtensions
{
    private const int MaxQueryDepth = 5;
    private const int MaxQueryComplexity = 100;
    private const int MaxQueryNodes = 50;

    public static IServiceCollection AddGraphQLApi(this IServiceCollection services)
    {
        services
            .AddGraphQLServer()
            .AddQueryType<Query>()
            .AddMutationType<Mutation>()
            .AddProjections()
            .AddFiltering()
            .AddSorting()
            .AddErrorFilter<GraphQLErrorFilter>()
            .AddDataLoader<StudentByIdDataLoader>()
            .AddDataLoader<SubjectByIdDataLoader>()
            .AddDataLoader<ProfessorByIdDataLoader>()
            // Security: Query depth, complexity, and execution limits
            .ModifyRequestOptions(ConfigureRequestOptions)
            .AddMaxExecutionDepthRule(MaxQueryDepth)
            // Cost analysis for query complexity
            .ModifyCostOptions(opt =>
            {
                opt.MaxFieldCost = MaxQueryComplexity;
                opt.MaxTypeCost = MaxQueryComplexity;
                opt.EnforceCostLimits = true;
            })
            // Pagination limits to prevent large result sets
            .ModifyPagingOptions(opt =>
            {
                opt.MaxPageSize = MaxQueryNodes;
                opt.DefaultPageSize = 20;
                opt.IncludeTotalCount = true;
            });

        return services;
    }

    private static void ConfigureRequestOptions(RequestExecutorOptions opt)
    {
        opt.IncludeExceptionDetails = false; // Don't expose internal errors in production
        opt.ExecutionTimeout = TimeSpan.FromSeconds(30);
    }
}
