// EN: Swagger Document Filter to add /connect/token endpoint
// VI: Swagger Document Filter để thêm /connect/token endpoint

using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace IamService.API.Swagger;

/// <summary>
/// EN: Adds OAuth2 /connect/token endpoint to Swagger documentation.
/// VI: Thêm OAuth2 /connect/token endpoint vào Swagger documentation.
/// </summary>
public class TokenEndpointDocumentFilter : IDocumentFilter
{
    public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
    {
        // EN: Add /connect/token endpoint
        // VI: Thêm /connect/token endpoint
        var tokenPath = new OpenApiPathItem();
        
        var postOperation = new OpenApiOperation
        {
            Tags = new List<OpenApiTag> { new() { Name = "OAuth2 Token" } },
            Summary = "OAuth2 Token Endpoint",
            Description = """
                OAuth2/OIDC token endpoint for authentication.
                
                **Supported Grant Types:**
                - `password` - Resource Owner Password Grant (login with email/password)
                - `refresh_token` - Refresh an access token
                - `client_credentials` - Service-to-service authentication
                
                **Default Client:**
                - `client_id`: password-client
                - `client_secret`: password-client-secret
                """,
            OperationId = "OAuth2Token",
            RequestBody = new OpenApiRequestBody
            {
                Required = true,
                Content = new Dictionary<string, OpenApiMediaType>
                {
                    ["application/x-www-form-urlencoded"] = new OpenApiMediaType
                    {
                        Schema = new OpenApiSchema
                        {
                            Type = "object",
                            Required = new HashSet<string> { "grant_type", "client_id" },
                            Properties = new Dictionary<string, OpenApiSchema>
                            {
                                ["grant_type"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "OAuth2 grant type",
                                    Enum = new List<IOpenApiAny>
                                    {
                                        new OpenApiString("password"),
                                        new OpenApiString("refresh_token"),
                                        new OpenApiString("client_credentials")
                                    },
                                    Example = new OpenApiString("password")
                                },
                                ["client_id"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "OAuth2 client ID",
                                    Example = new OpenApiString("password-client")
                                },
                                ["client_secret"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "OAuth2 client secret",
                                    Example = new OpenApiString("password-client-secret")
                                },
                                ["username"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "User email (required for password grant)",
                                    Example = new OpenApiString("user@example.com")
                                },
                                ["password"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Format = "password",
                                    Description = "User password (required for password grant)",
                                    Example = new OpenApiString("Password123!")
                                },
                                ["refresh_token"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "Refresh token (required for refresh_token grant)"
                                },
                                ["scope"] = new OpenApiSchema
                                {
                                    Type = "string",
                                    Description = "Requested scopes (space-separated)",
                                    Example = new OpenApiString("openid profile email api offline_access")
                                }
                            }
                        }
                    }
                }
            },
            Responses = new OpenApiResponses
            {
                ["200"] = new OpenApiResponse
                {
                    Description = "Token response",
                    Content = new Dictionary<string, OpenApiMediaType>
                    {
                        ["application/json"] = new OpenApiMediaType
                        {
                            Schema = new OpenApiSchema
                            {
                                Type = "object",
                                Properties = new Dictionary<string, OpenApiSchema>
                                {
                                    ["access_token"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Description = "JWT access token"
                                    },
                                    ["token_type"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Example = new OpenApiString("Bearer")
                                    },
                                    ["expires_in"] = new OpenApiSchema
                                    {
                                        Type = "integer",
                                        Description = "Token lifetime in seconds",
                                        Example = new OpenApiInteger(900)
                                    },
                                    ["refresh_token"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Description = "Refresh token (if offline_access scope requested)"
                                    },
                                    ["scope"] = new OpenApiSchema
                                    {
                                        Type = "string",
                                        Description = "Granted scopes"
                                    }
                                }
                            }
                        }
                    }
                },
                ["400"] = new OpenApiResponse
                {
                    Description = "Invalid request (missing parameters, invalid grant, etc.)"
                },
                ["401"] = new OpenApiResponse
                {
                    Description = "Invalid credentials or client authentication failed"
                }
            }
        };
        
        tokenPath.Operations.Add(OperationType.Post, postOperation);
        swaggerDoc.Paths.Add("/connect/token", tokenPath);
    }
}
