using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;

namespace ZB.MOM.WW.Auth.AspNetCore;

/// <summary>
/// Applies the hardened cookie-authentication defaults shared by ZB.MOM.WW apps:
/// HTTP-only, <see cref="SameSiteMode.Strict"/>, sliding expiration, a caller-supplied idle
/// timeout, and a configurable HTTPS requirement.
/// </summary>
/// <remarks>
/// The cookie <em>name</em> is intentionally left untouched: each app owns its own cookie name
/// (so two apps on the same host do not clobber each other's session), and the caller sets it
/// when configuring the cookie scheme.
/// </remarks>
public static class ZbCookieDefaults
{
    /// <summary>
    /// Default idle timeout used when a caller does not supply one. After this much inactivity
    /// the (sliding) session cookie expires and the principal must re-authenticate.
    /// </summary>
    public static readonly TimeSpan DefaultIdleTimeout = TimeSpan.FromMinutes(30);

    /// <summary>
    /// Applies the hardened defaults to <paramref name="options"/>.
    /// </summary>
    /// <param name="options">The cookie-authentication options to mutate.</param>
    /// <param name="requireHttps">
    /// When <see langword="true"/> (the default), the cookie is only ever sent over HTTPS
    /// (<see cref="CookieSecurePolicy.Always"/>). Set to <see langword="false"/> only for local
    /// development over plain HTTP (<see cref="CookieSecurePolicy.SameAsRequest"/>: Secure is
    /// still set when the current request is HTTPS, which is safer than <c>None</c>).
    /// </param>
    /// <param name="idleTimeout">
    /// The sliding idle timeout. Defaults to <see cref="DefaultIdleTimeout"/> when not specified.
    /// </param>
    /// <exception cref="ArgumentNullException"><paramref name="options"/> is <see langword="null"/>.</exception>
    public static void Apply(
        CookieAuthenticationOptions options,
        bool requireHttps = true,
        TimeSpan? idleTimeout = null)
    {
        ArgumentNullException.ThrowIfNull(options);

        options.Cookie.HttpOnly = true;
        options.Cookie.SameSite = SameSiteMode.Strict;
        options.Cookie.SecurePolicy = requireHttps
            ? CookieSecurePolicy.Always
            : CookieSecurePolicy.SameAsRequest;

        options.SlidingExpiration = true;
        options.ExpireTimeSpan = idleTimeout ?? DefaultIdleTimeout;
    }
}
