// ***********************************************************************
// 
//     Heath
// 
// ***********************************************************************
using Asp.Versioning.ApiExplorer;
using Core.Cerberos.Adapters.Common.Constants;
using Core.Cerberos.Adapters.Extensions;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
namespace Core.Cerberos.Adapters.Extensions
{
    /// 
    /// Extension methods for configuring Swagger documentation and UI.
    /// 
    public static class SwaggerExtensions
    {
        private static readonly string? environment = Environment.GetEnvironmentVariable(EnvironmentVariables.Stage);
        /// 
        /// Adds Swagger services to the specified .
        /// 
        /// The  to add the services to.
        public static void AddSwagger(this IServiceCollection services, IConfiguration configuration, string DocumentationFile, AuthSettings authSettings)
        {
            services.AddEndpointsApiExplorer();
            services.AddSwaggerGen(configuration, DocumentationFile, authSettings);
            services.AddTransient, ConfigureSwaggerOptions>();
        }
        /// 
        /// Configures Swagger generation with OAuth2 security and XML comments.
        /// 
        /// The  to add the services to.
        /// The  containing Swagger and OAuth2 configuration settings.
        public static void AddSwaggerGen(this IServiceCollection services, IConfiguration configuration, string DocumentationFile, AuthSettings authSettings)
        {
            services.AddSwaggerGen(c =>
                {
                    c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
                    {
                        Description = "OAuth2.0 Authorization Code flow",
                        Name = "oauth2.0",
                        Type = SecuritySchemeType.OAuth2,
                        Flows = new OpenApiOAuthFlows
                        {
                            AuthorizationCode = new OpenApiOAuthFlow
                            {
                                AuthorizationUrl = new Uri(authSettings.HeathCerberosAppAuthorizationUrl ?? string.Empty),
                                TokenUrl = new Uri(authSettings.HeathCerberosAppTokenUrl ?? string.Empty),
                                Scopes = new Dictionary
                                {
                                { authSettings.HeathCerberosAppScope ?? string.Empty, "Access API as User" }
                                }
                            }
                        }
                    });
                    c.AddSecurityRequirement(new OpenApiSecurityRequirement
                    {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" }
                        },
                        new[] { authSettings.HeathCerberosAppScope }
                    }
                    });
                    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                    {
                        Description = "JWT Authorization header using the Bearer scheme",
                        Name = "Authorization",
                        In = ParameterLocation.Header,
                        Type = SecuritySchemeType.Http,
                        Scheme = "bearer",
                        BearerFormat = "JWT"
                    });
                    c.AddSecurityRequirement(new OpenApiSecurityRequirement
                    {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        Array.Empty()
                    }
                    });
                    var filePath = Path.Combine(AppContext.BaseDirectory, DocumentationFile);
                    c.IncludeXmlComments(filePath);
                    c.SchemaFilter();
                });
        }
        /// 
        /// Configures Swagger and Swagger UI for the application.
        /// 
        /// The  instance.
        /// The  containing Swagger configuration settings.
        public static void ConfigureSwagger(this WebApplication app, IConfiguration configuration)
        {
            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                foreach (var version in app.DescribeApiVersions().Select(version => version.GroupName))
                    options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version);
                options.DisplayRequestDuration();
                options.EnableTryItOutByDefault();
                options.DocExpansion(DocExpansion.None);
            });
        }
        /// 
        /// Configures Swagger UI for the application with OAuth2 settings.
        /// 
        /// The  instance.
        /// The  containing Swagger UI and OAuth2 configuration settings.
        public static void UseSwaggerUI(this WebApplication app, IConfiguration configuration, AuthSettings authSettings)
        {
            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Custom Auth API with Azure AD v1");
                options.OAuthClientId(authSettings.HeathCerberosAppClientId);
                options.OAuthUsePkce();
                options.OAuthScopeSeparator(" ");
            });
        }
        /// 
        /// Adds API versioning and API explorer to the application.
        /// 
        /// The  to add the services to.
        /// The modified  instance.
        public static IServiceCollection AddVersioning(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddApiVersioning(options => options.ReportApiVersions = true)
                   .AddApiExplorer(options =>
                   {
                       options.GroupNameFormat = "'v'VVV";
                       options.SubstituteApiVersionInUrl = true;
                   });
            return services;
        }
    }
    /// 
    /// Configures Swagger generation options.
    /// 
    public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions
    {
        /// 
        /// Configures SwaggerGen options.
        /// 
        /// The SwaggerGen options to configure.
        public void Configure(SwaggerGenOptions options)
        {
            foreach (var description in provider.ApiVersionDescriptions)
            {
                options.SwaggerDoc(description.GroupName, new OpenApiInfo
                {
                    Title = AppDomain.CurrentDomain.FriendlyName,
                    Version = description.ApiVersion.ToString()
                });
            }
            // Map DateOnly type to Swagger schema
            options.MapType(() => new OpenApiSchema
            {
                Type = "string",
                Format = "date",
                Example = new OpenApiString(DateOnly.MinValue.ToString())
            });
            // Customize schema IDs for Swagger
            options.CustomSchemaIds(type => type.ToString().Replace("+", "."));
        }
    }
}