using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

namespace ZB.MOM.WW.MxGateway.Server.Dashboard;

/// <summary>
/// Extension methods for configuring the gateway dashboard services.
/// </summary>
public static class DashboardServiceCollectionExtensions
{
    /// <summary>
    /// Registers all dashboard services, authentication, and Razor components.
    /// </summary>
    /// <param name="services">Service collection to register services.</param>
    public static IServiceCollection AddGatewayDashboard(this IServiceCollection services)
    {
        services.AddSingleton<IDashboardSnapshotService, DashboardSnapshotService>();
        services.AddSingleton<IDashboardLiveDataService, DashboardLiveDataService>();
        services.AddSingleton<IDashboardAuthenticator, DashboardAuthenticator>();
        services.AddSingleton<DashboardApiKeyAuthorization>();
        services.AddSingleton<IDashboardApiKeyManagementService, DashboardApiKeyManagementService>();
        services.AddSingleton<IDashboardSessionAdminService, DashboardSessionAdminService>();
        services.AddSingleton<HubTokenService>();
        services.AddScoped<Hubs.DashboardHubConnectionFactory>();
        services.AddSingleton<Hubs.IDashboardEventBroadcaster, Hubs.DashboardEventBroadcaster>();
        services.AddHostedService<Hubs.DashboardSnapshotPublisher>();
        services.AddHostedService<Hubs.AlarmsHubPublisher>();
        services.AddHttpContextAccessor();
        services.AddAntiforgery();
        services.AddCascadingAuthenticationState();
        services.AddRazorComponents()
            .AddInteractiveServerComponents();
        services.AddSignalR();

        services
            .AddAuthentication(DashboardAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(DashboardAuthenticationDefaults.AuthenticationScheme, cookieOptions =>
            {
                cookieOptions.Cookie.Name = DashboardAuthenticationDefaults.CookieName;
                cookieOptions.Cookie.HttpOnly = true;
                cookieOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always;
                cookieOptions.Cookie.SameSite = SameSiteMode.Strict;
                cookieOptions.Cookie.Path = "/";
                cookieOptions.LoginPath = "/login";
                cookieOptions.LogoutPath = "/logout";
                cookieOptions.AccessDeniedPath = "/denied";
                cookieOptions.ExpireTimeSpan = TimeSpan.FromHours(8);
                cookieOptions.SlidingExpiration = true;
            })
            .AddScheme<AuthenticationSchemeOptions, HubTokenAuthenticationHandler>(
                DashboardAuthenticationDefaults.HubAuthenticationScheme,
                _ => { });

        services.AddAuthorization(authorization =>
        {
            authorization.AddPolicy(
                DashboardAuthenticationDefaults.ViewerPolicy,
                policy => policy.AddRequirements(DashboardAuthorizationRequirement.AnyDashboardRole));
            authorization.AddPolicy(
                DashboardAuthenticationDefaults.AdminPolicy,
                policy => policy.AddRequirements(DashboardAuthorizationRequirement.AdminOnly));
            authorization.AddPolicy(
                DashboardAuthenticationDefaults.HubClientsPolicy,
                policy => policy
                    .AddAuthenticationSchemes(
                        DashboardAuthenticationDefaults.AuthenticationScheme,
                        DashboardAuthenticationDefaults.HubAuthenticationScheme)
                    .AddRequirements(DashboardAuthorizationRequirement.AnyDashboardRole));
        });
        services.AddSingleton<IAuthorizationHandler, DashboardAuthorizationHandler>();

        return services;
    }
}
