using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace DocumentOperator.API.Configuration
{
    /// <summary>
    /// Swagger document filter that merges operations with same path but different [Consumes] attributes.
    /// Ensures both multipart/form-data and application/json variants are visible in Swagger UI.
    /// </summary>
    public class DualInputDocumentFilter : IDocumentFilter
    {
        private readonly IApiDescriptionGroupCollectionProvider _apiDescriptionProvider;

        /// <summary>
        /// Initializes a new instance of the <see cref="DualInputDocumentFilter"/> class.
        /// </summary>
        /// <param name="apiDescriptionProvider">API description provider to access all endpoints</param>
        public DualInputDocumentFilter(IApiDescriptionGroupCollectionProvider apiDescriptionProvider)
        {
            _apiDescriptionProvider = apiDescriptionProvider;
        }

        /// <summary>
        /// Applies the filter to merge operations with different content types.
        /// </summary>
        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
        {
            var allApiDescriptions = _apiDescriptionProvider.ApiDescriptionGroups.Items
                .SelectMany(g => g.Items)
                .ToList();

            // Group by path
            var groupedByPath = allApiDescriptions
                .GroupBy(x => "/" + x.RelativePath)
                .ToList();

            foreach (var group in groupedByPath)
            {
                var path = group.Key;

                if (!swaggerDoc.Paths.ContainsKey(path))
                    continue;

                var pathItem = swaggerDoc.Paths[path];

                // Find multipart and JSON variants
                var multipartDesc = group.FirstOrDefault(x =>
                    x.SupportedRequestFormats.Any(f => f.MediaType == "multipart/form-data"));

                var jsonDesc = group.FirstOrDefault(x =>
                    x.SupportedRequestFormats.Any(f => f.MediaType == "application/json"));

                // If we have both variants, merge them into single operation
                if (multipartDesc != null && jsonDesc != null)
                {
                    var httpMethod = multipartDesc.HttpMethod?.ToLowerInvariant();
                    OperationType operationType;

                    if (!Enum.TryParse<OperationType>(httpMethod, true, out operationType))
                        continue;

                    if (!pathItem.Operations.ContainsKey(operationType))
                        continue;

                    var operation = pathItem.Operations[operationType];

                    // Ensure RequestBody exists
                    if (operation.RequestBody == null)
                    {
                        operation.RequestBody = new OpenApiRequestBody
                        {
                            Required = true,
                            Content = new Dictionary<string, OpenApiMediaType>()
                        };
                    }

                    // Add multipart/form-data if missing
                    if (!operation.RequestBody.Content.ContainsKey("multipart/form-data"))
                    {
                        operation.RequestBody.Content.Add("multipart/form-data", new OpenApiMediaType
                        {
                            Schema = new OpenApiSchema
                            {
                                Type = "object",
                                Properties = new Dictionary<string, OpenApiSchema>
                                {
                                    ["file"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Format = "binary",
                                        Description = "PDF file to upload"
                                    }
                                },
                                Required = new HashSet<string> { "file" }
                            }
                        });
                    }

                    // Add application/json if missing
                    if (!operation.RequestBody.Content.ContainsKey("application/json"))
                    {
                        operation.RequestBody.Content.Add("application/json", new OpenApiMediaType
                        {
                            Schema = new OpenApiSchema
                            {
                                Type = "object",
                                Properties = new Dictionary<string, OpenApiSchema>
                                {
                                    ["base64Pdf"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Format = "byte",
                                        Description = "Base64-encoded PDF file content"
                                    }
                                },
                                Required = new HashSet<string> { "base64Pdf" }
                            }
                        });
                    }
                }
            }
        }
    }
}
