using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.MxGateway.Server;
using ZB.MOM.WW.MxGateway.Server.Dashboard;

namespace ZB.MOM.WW.MxGateway.Tests.Gateway.Dashboard;

public sealed class DashboardCookieOptionsTests
{
    /// <summary>
    /// Verifies that the application configures secure dashboard authentication cookies.
    /// With <c>RequireHttpsCookie</c> defaulting to <see langword="true"/> and no explicit
    /// <c>CookieName</c> override, the cookie is named with the <c>__Host-</c> prefix so
    /// browsers enforce the Secure/no-Domain/Path=/ guarantees the prefix promises.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_ConfiguresSecureDashboardCookie()
    {
        await using WebApplication app = GatewayApplication.Build([]);
        IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
            .GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();

        CookieAuthenticationOptions options = optionsMonitor.Get(
            DashboardAuthenticationDefaults.AuthenticationScheme);

        Assert.Equal(DashboardAuthenticationDefaults.SecureCookieName, options.Cookie.Name);
        Assert.True(options.Cookie.HttpOnly);
        Assert.Equal(CookieSecurePolicy.Always, options.Cookie.SecurePolicy);
        Assert.Equal(SameSiteMode.Strict, options.Cookie.SameSite);
        Assert.Equal("/", options.Cookie.Path);
        Assert.Equal("/login", options.LoginPath);
        Assert.Equal("/logout", options.LogoutPath);
        Assert.Equal("/denied", options.AccessDeniedPath);
    }

    /// <summary>
    /// Verifies that setting <c>MxGateway:Dashboard:RequireHttpsCookie=false</c>
    /// relaxes the cookie to <see cref="CookieSecurePolicy.SameAsRequest"/> so
    /// the dashboard can be reached over plain HTTP in dev, and that the plain
    /// <see cref="DashboardAuthenticationDefaults.CookieName"/> is used rather than the
    /// <c>__Host-</c> name — a <c>__Host-</c> cookie without a guaranteed Secure flag is
    /// silently dropped by browsers.
    /// </summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_WithRequireHttpsCookieFalse_UsesSameAsRequestAndPlainName()
    {
        await using WebApplication app = GatewayApplication.Build(
            ["--MxGateway:Dashboard:RequireHttpsCookie=false"]);
        IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
            .GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();

        CookieAuthenticationOptions options = optionsMonitor.Get(
            DashboardAuthenticationDefaults.AuthenticationScheme);

        Assert.Equal(CookieSecurePolicy.SameAsRequest, options.Cookie.SecurePolicy);
        Assert.Equal(DashboardAuthenticationDefaults.CookieName, options.Cookie.Name);
    }

    /// <summary>
    /// Verifies that an explicit <c>MxGateway:Dashboard:CookieName</c> override wins over the
    /// secure <c>__Host-</c> default (this build leaves <c>RequireHttpsCookie</c> at its
    /// <see langword="true"/> default), so a gateway instance sharing a hostname with another
    /// can be given a distinct name (browser cookies are scoped by host+path, not port).
    /// </summary>
    /// <returns>A task that represents the asynchronous operation.</returns>
    [Fact]
    public async Task Build_WithCookieNameOverride_UsesConfiguredName()
    {
        await using WebApplication app = GatewayApplication.Build(
            ["--MxGateway:Dashboard:CookieName=MxGatewayDashboard.env2"]);
        IOptionsMonitor<CookieAuthenticationOptions> optionsMonitor = app.Services
            .GetRequiredService<IOptionsMonitor<CookieAuthenticationOptions>>();

        CookieAuthenticationOptions options = optionsMonitor.Get(
            DashboardAuthenticationDefaults.AuthenticationScheme);

        Assert.Equal("MxGatewayDashboard.env2", options.Cookie.Name);
    }
}
