using Codex.CQRS.Commands;
using Codex.CQRS.Queries;
using Codex.Dal.QueryProviders;
using Microsoft.AspNetCore.Mvc;
using Microsoft.OpenApi.Models;
using OpenHarbor.CQRS.Abstractions;
using OpenHarbor.CQRS.DynamicQuery.Abstractions;
using PoweredSoft.Data.Core;
using PoweredSoft.DynamicQuery;
using PoweredSoft.DynamicQuery.Core;

namespace Codex.Api.Endpoints;

/// <summary>
/// Manual endpoint registration to ensure proper OpenAPI documentation for all CQRS endpoints.
/// Required because OpenHarbor.CQRS doesn't auto-generate Swagger docs for commands with return values and dynamic queries.
/// </summary>
public static class ManualEndpointRegistration
{
    public static WebApplication MapCodexEndpoints(this WebApplication app)
    {
        // ============================================================
        // COMMANDS
        // ============================================================

        // CreateAgent - No return value (already auto-documented by OpenHarbor)
        // UpdateAgent - No return value (already auto-documented by OpenHarbor)
        // DeleteAgent - No return value (already auto-documented by OpenHarbor)

        // CreateConversation - Returns Guid
        app.MapPost("/api/command/createConversation",
            async ([FromBody] CreateConversationCommand command,
                   ICommandHandler<CreateConversationCommand, Guid> handler) =>
            {
                var result = await handler.HandleAsync(command);
                return Results.Ok(new { id = result });
            })
            .WithName("CreateConversation")
            .WithTags("Commands")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "Creates a new conversation for grouping related messages",
                Description = "Returns the newly created conversation ID",
                RequestBody = new OpenApiRequestBody
                {
                    Required = true,
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        ["application/json"] = new OpenApiMediaType
                        {
                            Schema = new OpenApiSchema
                            {
                                Reference = new OpenApiReference
                                {
                                    Type = ReferenceType.Schema,
                                    Id = nameof(CreateConversationCommand)
                                }
                            }
                        }
                    }
                },
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Conversation created successfully",
                        Content = new Dictionary<string, OpenApiMediaType>
                        {
                            ["application/json"] = new OpenApiMediaType
                            {
                                Schema = new OpenApiSchema
                                {
                                    Type = "object",
                                    Properties = new Dictionary<string, OpenApiSchema>
                                    {
                                        ["id"] = new OpenApiSchema
                                        {
                                            Type = "string",
                                            Format = "uuid",
                                            Description = "The unique identifier of the created conversation"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    ["400"] = new OpenApiResponse { Description = "Validation failed" },
                    ["500"] = new OpenApiResponse { Description = "Internal server error" }
                }
            })
            .Produces<object>(200)
            .ProducesValidationProblem();

        // StartAgentExecution - Returns Guid
        app.MapPost("/api/command/startAgentExecution",
            async ([FromBody] StartAgentExecutionCommand command,
                   ICommandHandler<StartAgentExecutionCommand, Guid> handler) =>
            {
                var result = await handler.HandleAsync(command);
                return Results.Ok(new { id = result });
            })
            .WithName("StartAgentExecution")
            .WithTags("Commands")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "Starts a new agent execution with a user prompt",
                Description = "Creates an execution record and returns its ID. Use this to track agent runs.",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Execution started successfully",
                        Content = new Dictionary<string, OpenApiMediaType>
                        {
                            ["application/json"] = new OpenApiMediaType
                            {
                                Schema = new OpenApiSchema
                                {
                                    Type = "object",
                                    Properties = new Dictionary<string, OpenApiSchema>
                                    {
                                        ["id"] = new OpenApiSchema
                                        {
                                            Type = "string",
                                            Format = "uuid",
                                            Description = "The unique identifier of the execution"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    ["400"] = new OpenApiResponse { Description = "Validation failed" },
                    ["404"] = new OpenApiResponse { Description = "Agent not found" },
                    ["500"] = new OpenApiResponse { Description = "Internal server error" }
                }
            })
            .Produces<object>(200)
            .ProducesValidationProblem();

        // CompleteAgentExecution - No return value
        app.MapPost("/api/command/completeAgentExecution",
            async ([FromBody] CompleteAgentExecutionCommand command,
                   ICommandHandler<CompleteAgentExecutionCommand> handler) =>
            {
                await handler.HandleAsync(command);
                return Results.Ok();
            })
            .WithName("CompleteAgentExecution")
            .WithTags("Commands")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "Marks an agent execution as completed with results",
                Description = "Updates execution status, tokens used, and stores the response",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse { Description = "Execution completed successfully" },
                    ["400"] = new OpenApiResponse { Description = "Validation failed" },
                    ["404"] = new OpenApiResponse { Description = "Execution not found" },
                    ["500"] = new OpenApiResponse { Description = "Internal server error" }
                }
            })
            .Produces(200)
            .ProducesValidationProblem();

        // ============================================================
        // QUERIES
        // ============================================================

        // Health - Already auto-documented
        // GetAgent - Already auto-documented

        // GetAgentExecution
        app.MapPost("/api/query/getAgentExecution",
            async ([FromBody] GetAgentExecutionQuery query,
                   IQueryHandler<GetAgentExecutionQuery, AgentExecutionDetails?> handler) =>
            {
                var result = await handler.HandleAsync(query);
                return result != null ? Results.Ok(result) : Results.NotFound();
            })
            .WithName("GetAgentExecution")
            .WithTags("Queries")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "Get details of a specific agent execution by ID",
                Description = "Returns execution details including tokens, cost, messages, and status",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Execution details retrieved successfully",
                        Content = new Dictionary<string, OpenApiMediaType>
                        {
                            ["application/json"] = new OpenApiMediaType
                            {
                                Schema = new OpenApiSchema
                                {
                                    Reference = new OpenApiReference
                                    {
                                        Type = ReferenceType.Schema,
                                        Id = nameof(AgentExecutionDetails)
                                    }
                                }
                            }
                        }
                    },
                    ["404"] = new OpenApiResponse { Description = "Execution not found" },
                    ["500"] = new OpenApiResponse { Description = "Internal server error" }
                }
            })
            .Produces<AgentExecutionDetails>(200)
            .Produces(404);

        // GetConversation
        app.MapPost("/api/query/getConversation",
            async ([FromBody] GetConversationQuery query,
                   IQueryHandler<GetConversationQuery, ConversationDetails?> handler) =>
            {
                var result = await handler.HandleAsync(query);
                return result != null ? Results.Ok(result) : Results.NotFound();
            })
            .WithName("GetConversation")
            .WithTags("Queries")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "Get details of a specific conversation by ID",
                Description = "Returns conversation details including messages and execution history",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Conversation details retrieved successfully",
                        Content = new Dictionary<string, OpenApiMediaType>
                        {
                            ["application/json"] = new OpenApiMediaType
                            {
                                Schema = new OpenApiSchema
                                {
                                    Reference = new OpenApiReference
                                    {
                                        Type = ReferenceType.Schema,
                                        Id = nameof(ConversationDetails)
                                    }
                                }
                            }
                        }
                    },
                    ["404"] = new OpenApiResponse { Description = "Conversation not found" },
                    ["500"] = new OpenApiResponse { Description = "Internal server error" }
                }
            })
            .Produces<ConversationDetails>(200)
            .Produces(404);

        // ============================================================
        // DYNAMIC QUERIES (Paginated Lists)
        // ============================================================
        // NOTE: Dynamic queries are auto-registered by OpenHarbor but not auto-documented.
        // They work via /api/dynamicquery/{ItemType} but aren't in Swagger without manual registration.
        // The endpoints exist and function - frontend can use them directly from openapi.json examples below.

        // Manual registration disabled for now - OpenHarbor handles these automatically
        // TODO: Add proper schema documentation for dynamic query request/response

        /*
        // ListAgents
        app.MapPost("/api/dynamicquery/ListAgentsQueryItem",
            async (HttpContext context,
                   IQueryableProvider<ListAgentsQueryItem> provider,
                   IAsyncQueryableService queryService) =>
            {
                var query = await context.Request.ReadFromJsonAsync<object>();
                var queryable = await provider.GetQueryableAsync(query!);
                var result = await queryService.ExecuteAsync(queryable, query!);
                return Results.Ok(result);
            })
            .WithName("ListAgents")
            .WithTags("DynamicQuery")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "List agents with filtering, sorting, and pagination",
                Description = @"Dynamic query endpoint supporting:
- **Filtering**: Filter by any property (Name, Type, Status, etc.)
- **Sorting**: Sort by one or multiple properties
- **Pagination**: Page and PageSize parameters
- **Aggregates**: Count, Sum, Average on numeric fields

### Example Request
```json
{
  ""filters"": [
    { ""path"": ""Name"", ""operator"": ""Contains"", ""value"": ""search"" },
    { ""path"": ""Status"", ""operator"": ""Equal"", ""value"": ""Active"" }
  ],
  ""sorts"": [{ ""path"": ""CreatedAt"", ""descending"": true }],
  ""page"": 1,
  ""pageSize"": 20
}
```",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Paginated list of agents",
                        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 = new OpenApiSchema
                                            {
                                                Reference = new OpenApiReference
                                                {
                                                    Type = ReferenceType.Schema,
                                                    Id = nameof(ListAgentsQueryItem)
                                                }
                                            }
                                        },
                                        ["page"] = new OpenApiSchema { Type = "integer" },
                                        ["pageSize"] = new OpenApiSchema { Type = "integer" },
                                        ["totalCount"] = new OpenApiSchema { Type = "integer" }
                                    }
                                }
                            }
                        }
                    }
                }
            })
            .Produces<object>(200);

        // ListConversations
        app.MapPost("/api/dynamicquery/ListConversationsQueryItem",
            async (HttpContext context,
                   IQueryableProvider<ListConversationsQueryItem> provider,
                   IAsyncQueryableService queryService) =>
            {
                var query = await context.Request.ReadFromJsonAsync<object>();
                var queryable = await provider.GetQueryableAsync(query!);
                var result = await queryService.ExecuteAsync(queryable, query!);
                return Results.Ok(result);
            })
            .WithName("ListConversations")
            .WithTags("DynamicQuery")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "List conversations with filtering, sorting, and pagination",
                Description = "Returns paginated conversations with message counts and metadata",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Paginated list of conversations",
                        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 = new OpenApiSchema
                                            {
                                                Reference = new OpenApiReference
                                                {
                                                    Type = ReferenceType.Schema,
                                                    Id = nameof(ListConversationsQueryItem)
                                                }
                                            }
                                        },
                                        ["totalCount"] = new OpenApiSchema { Type = "integer" }
                                    }
                                }
                            }
                        }
                    }
                }
            })
            .Produces<object>(200);

        // ListAgentExecutions
        app.MapPost("/api/dynamicquery/ListAgentExecutionsQueryItem",
            async (HttpContext context,
                   IQueryableProvider<ListAgentExecutionsQueryItem> provider,
                   IAsyncQueryableService queryService) =>
            {
                var query = await context.Request.ReadFromJsonAsync<object>();
                var queryable = await provider.GetQueryableAsync(query!);
                var result = await queryService.ExecuteAsync(queryable, query!);
                return Results.Ok(result);
            })
            .WithName("ListAgentExecutions")
            .WithTags("DynamicQuery")
            .WithOpenApi(operation => new(operation)
            {
                Summary = "List agent executions with filtering, sorting, and pagination",
                Description = "Returns paginated execution history with tokens, costs, and status",
                Responses = new OpenApiResponses
                {
                    ["200"] = new OpenApiResponse
                    {
                        Description = "Paginated list of executions",
                        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 = new OpenApiSchema
                                            {
                                                Reference = new OpenApiReference
                                                {
                                                    Type = ReferenceType.Schema,
                                                    Id = nameof(ListAgentExecutionsQueryItem)
                                                }
                                            }
                                        },
                                        ["totalCount"] = new OpenApiSchema { Type = "integer" }
                                    }
                                }
                            }
                        }
                    }
                }
            })
            .Produces<object>(200);
        */

        return app;
    }
}
