using Codex.Dal.QueryProviders;
using Microsoft.OpenApi.Models;
using PoweredSoft.DynamicQuery;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace Codex.Api.Swagger;

/// <summary>
/// Document filter that adds dynamic query endpoints to OpenAPI specification.
/// OpenHarbor.CQRS dynamic queries create runtime endpoints that Swagger cannot auto-discover.
/// </summary>
public class DynamicQueryDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // Add ListAgentsQueryItem endpoint
        AddDynamicQueryEndpoint<ListAgentsQueryItem>(
            swaggerDoc,
            "ListAgentsQueryItem",
            "List agents with filtering, sorting, and pagination");

        // Add ListConversationsQueryItem endpoint
        AddDynamicQueryEndpoint<ListConversationsQueryItem>(
            swaggerDoc,
            "ListConversationsQueryItem",
            "List conversations with filtering, sorting, and pagination");

        // Add ListAgentExecutionsQueryItem endpoint
        AddDynamicQueryEndpoint<ListAgentExecutionsQueryItem>(
            swaggerDoc,
            "ListAgentExecutionsQueryItem",
            "List agent executions with filtering, sorting, and pagination");
    }

    private static void AddDynamicQueryEndpoint<T>(
        OpenApiDocument swaggerDoc,
        string itemTypeName,
        string description) where T : class
    {
        // Create schema reference for the item type
        var itemSchema = new OpenApiSchema
        {
            Reference = new OpenApiReference
            {
                Type = ReferenceType.Schema,
                Id = itemTypeName
            }
        };
        var path = $"/api/dynamicquery/{itemTypeName}";

        var operation = new OpenApiOperation
        {
            Tags = new List<OpenApiTag>
            {
                new OpenApiTag { Name = "DynamicQuery" }
            },
            Summary = description,
            Description = @"Dynamic query endpoint supporting:
- **Filtering**: Filter by any property using operators (Equal, Contains, GreaterThan, etc.)
- **Sorting**: Sort by one or multiple properties (ascending/descending)
- **Pagination**: Page and PageSize parameters
- **Aggregates**: Count, Sum, Average, Min, Max on numeric fields

### Request Body Example
```json
{
  ""filters"": [
    {
      ""path"": ""Name"",
      ""operator"": ""Contains"",
      ""value"": ""search term""
    }
  ],
  ""sorts"": [
    {
      ""path"": ""CreatedAt"",
      ""descending"": true
    }
  ],
  ""page"": 1,
  ""pageSize"": 20
}
```

### Supported Filter Operators
- Equal, NotEqual
- Contains, StartsWith, EndsWith
- GreaterThan, GreaterThanOrEqual
- LessThan, LessThanOrEqual
- In, NotIn",
            RequestBody = new OpenApiRequestBody
            {
                Required = true,
                Description = "Dynamic query request with filters, sorts, and pagination",
                Content = new Dictionary<string, OpenApiMediaType>
                {
                    ["application/json"] = new OpenApiMediaType
                    {
                        Schema = new OpenApiSchema
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.Schema,
                                Id = "DynamicQueryRequest"
                            }
                        }
                    }
                }
            },
            Responses = new OpenApiResponses
            {
                ["200"] = new OpenApiResponse
                {
                    Description = "Successful query with paginated results",
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        ["application/json"] = new OpenApiMediaType
                        {
                            Schema = new OpenApiSchema
                            {
                                Type = "object",
                                Properties = new Dictionary<string, OpenApiSchema>
                                {
                                    ["data"] = new OpenApiSchema
                                    {
                                        Type = "array",
                                        Items = itemSchema
                                    },
                                    ["page"] = new OpenApiSchema
                                    {
                                        Type = "integer",
                                        Description = "Current page number"
                                    },
                                    ["pageSize"] = new OpenApiSchema
                                    {
                                        Type = "integer",
                                        Description = "Number of items per page"
                                    },
                                    ["totalCount"] = new OpenApiSchema
                                    {
                                        Type = "integer",
                                        Description = "Total number of items matching the query"
                                    },
                                    ["aggregates"] = new OpenApiSchema
                                    {
                                        Type = "object",
                                        Description = "Aggregate calculations (if requested)",
                                        AdditionalPropertiesAllowed = true
                                    }
                                }
                            }
                        }
                    }
                },
                ["400"] = new OpenApiResponse
                {
                    Description = "Invalid query parameters or filter syntax"
                },
                ["500"] = new OpenApiResponse
                {
                    Description = "Internal server error"
                }
            }
        };

        var pathItem = new OpenApiPathItem
        {
            Operations = new Dictionary<OperationType, OpenApiOperation>
            {
                [OperationType.Post] = operation
            }
        };

        swaggerDoc.Paths.Add(path, pathItem);
    }
}
