using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using OpenIddict.Abstractions;
using Quartz;

namespace Fengling.AuthService.Configuration;

public static class OpenIddictSetup
{
    public static IServiceCollection AddOpenIddictConfiguration(
        this IServiceCollection services,
        IConfiguration configuration
    )
    {
        
        services.Configure<IdentityOptions>(options =>
        {
            options.ClaimsIdentity.UserNameClaimType = OpenIddictConstants.Claims.Name;
            options.ClaimsIdentity.UserIdClaimType = OpenIddictConstants.Claims.Subject;
            options.ClaimsIdentity.RoleClaimType = OpenIddictConstants.Claims.Role;
            options.ClaimsIdentity.EmailClaimType = OpenIddictConstants.Claims.Email;
            options.SignIn.RequireConfirmedAccount = false;
        });
        
        services.AddQuartz(options =>
        {
            options.UseSimpleTypeLoader();
            options.UseInMemoryStore();
        });
        var isTesting = configuration.GetValue<bool>("Testing", false);

        var builder = services.AddOpenIddict();

        builder.AddCore(options =>
        {
            options.UseEntityFrameworkCore()
                .UseDbContext<Data.ApplicationDbContext>();
            options.UseQuartz();
        });

        if (!isTesting)
        {
            builder.AddServer(options =>
            {
                options.SetIssuer(configuration["OpenIddict:Issuer"] ?? "http://localhost:5132");
                
                options.SetAuthorizationEndpointUris("connect/authorize")
                    .SetIntrospectionEndpointUris("connect/introspect")
                    .SetEndSessionEndpointUris("connect/endsession")
                    .SetTokenEndpointUris("connect/token")
                    .SetUserInfoEndpointUris("connect/userinfo")
                    .SetEndUserVerificationEndpointUris("connect/verify");
                
                options.AllowAuthorizationCodeFlow()
                    .AllowHybridFlow()
                    .AllowClientCredentialsFlow()
                    .AllowRefreshTokenFlow();
                
                options.AddDevelopmentEncryptionCertificate()
                       .AddDevelopmentSigningCertificate();

                options.DisableAccessTokenEncryption();

                options.RegisterScopes(OpenIddictConstants.Scopes.OfflineAccess, OpenIddictConstants.Scopes.Email,
                    OpenIddictConstants.Scopes.Profile, OpenIddictConstants.Scopes.OpenId,
                    OpenIddictConstants.Permissions.Scopes.Roles,
                    "api",
                    "auth_server_admin");
                
                options
                    .UseReferenceAccessTokens()
                    .UseReferenceRefreshTokens()
                    .UseAspNetCore()
                    .DisableTransportSecurityRequirement()
                    .EnableAuthorizationEndpointPassthrough()
                    .EnableEndSessionEndpointPassthrough()
                    .EnableTokenEndpointPassthrough()
                    .EnableUserInfoEndpointPassthrough()
                    .EnableStatusCodePagesIntegration();

                options.SetAccessTokenLifetime(TimeSpan.FromHours(24));
            });
        }

        builder.AddValidation(options =>
        {
            options.UseLocalServer();
            options.UseAspNetCore();
        });

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);

        return services;
    }
}
